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 #include <osgDB/WriteFile>
22 
23 #include <limits.h>
24 
25 
26 #define REPORT_TIME 0
27 
28 #if REPORT_TIME
29 #include <osg/Timer>
30 #endif
31 
32 namespace osgText
33 {
34 
35 /////////////////////////////////////////////////////////////////////////////////////////
36 //
37 // Boundary
38 //
39 class Boundary : public osg::Referenced
40 {
41 public:
42 
43     struct Segment
44     {
SegmentosgText::Boundary::Segment45         Segment(unsigned int f, unsigned int s, float t):
46             first(f), second(s), thickness(t), suggestedThickness(t)  {}
47 
SegmentosgText::Boundary::Segment48         Segment(const Segment& seg):
49             first(seg.first),
50             second(seg.second),
51             thickness(seg.thickness),
52             suggestedThickness(seg.suggestedThickness) {}
53 
operator =osgText::Boundary::Segment54         Segment& operator = (const Segment& seg)
55         {
56             first = seg.first;
57             second = seg.second;
58             thickness = seg.thickness;
59             suggestedThickness = seg.suggestedThickness;
60             return *this;
61         }
62 
63         unsigned int    first;
64         unsigned int    second;
65         float           thickness;
66         float           suggestedThickness;
67     };
68 
69 
70     //typedef std::pair<unsigned int, unsigned int> Segment;
71     typedef std::vector<Segment>  Segments;
72     osg::ref_ptr<const osg::Vec3Array> _vertices;
73     osg::ref_ptr<const osg::DrawElementsUShort> _elements;
74     Segments _segments;
75     bool verbose;
76 
Boundary(const osg::Vec3Array * vertices,const osg::PrimitiveSet * primitiveSet,float thickness)77     Boundary(const osg::Vec3Array* vertices, const osg::PrimitiveSet* primitiveSet, float thickness):
78         verbose(false)
79     {
80         const osg::DrawArrays* drawArrays = dynamic_cast<const osg::DrawArrays*>(primitiveSet);
81         if (drawArrays)
82         {
83             set(vertices, drawArrays->getFirst(), drawArrays->getCount(), thickness);
84         }
85         else
86         {
87             const osg::DrawElementsUShort* elements = dynamic_cast<const osg::DrawElementsUShort*>(primitiveSet);
88             if (elements) set(vertices, elements, thickness);
89         }
90     }
91 
set(const osg::Vec3Array * vertices,unsigned int start,unsigned int count,float thickness)92     void set(const osg::Vec3Array* vertices, unsigned int start, unsigned int count, float thickness)
93     {
94         osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::POLYGON);
95         for(unsigned int i=start; i<start+count; ++i)
96         {
97             elements->push_back(i);
98         }
99 
100         set(vertices, elements, thickness);
101     }
102 
set(const osg::Vec3Array * vertices,const osg::DrawElementsUShort * elements,float thickness)103     void set(const osg::Vec3Array* vertices, const osg::DrawElementsUShort* elements, float thickness)
104     {
105         _vertices = vertices;
106         _elements = elements;
107 
108         _segments.clear();
109 
110         if (elements->empty()) return;
111 
112         _segments.reserve(elements->size()-1);
113         for(unsigned int i=0; i<elements->size()-1; ++i)
114         {
115             _segments.push_back( Segment((*elements)[i], (*elements)[i+1], thickness) );
116         }
117     }
118 
shorter(float original_thickness,float new_thickness) const119     bool shorter(float original_thickness, float new_thickness) const { return (original_thickness<0.0f) ? (new_thickness>original_thickness) : (new_thickness<original_thickness); }
120 
shorten(float & original_thickness,float new_thickness)121     bool shorten(float& original_thickness, float new_thickness) { if (shorter(original_thickness, new_thickness)) { original_thickness = new_thickness; return true; } else return false; }
122 
shortenBisector(unsigned int i,float new_thickness)123     bool shortenBisector(unsigned int i, float new_thickness)
124     {
125         bool r1 = shorten(_segments[(i+_segments.size()-1)%(_segments.size())].suggestedThickness, new_thickness);
126         bool r2 = shorten(_segments[i].suggestedThickness, new_thickness);
127         return r1 || r2;
128     }
129 
applySuggestedThickness()130     void applySuggestedThickness()
131     {
132         for(Segments::iterator itr = _segments.begin();
133             itr != _segments.end();
134             ++itr)
135         {
136             (*itr).thickness = (*itr).suggestedThickness;
137         }
138     }
139 
applyThickness(float thickness)140     void applyThickness(float thickness)
141     {
142         for(Segments::iterator itr = _segments.begin();
143             itr != _segments.end();
144             ++itr)
145         {
146             (*itr).thickness = thickness;
147             (*itr).suggestedThickness = thickness;
148         }
149     }
150 
getSuggestedThicknessRange(float & smallest,float & largest)151     void getSuggestedThicknessRange(float& smallest, float& largest)
152     {
153         for(Segments::iterator itr = _segments.begin();
154             itr != _segments.end();
155             ++itr)
156         {
157             float t = (*itr).suggestedThickness;
158             if (t<smallest) smallest = t;
159             if (t>largest) largest = t;
160         }
161 
162         if (largest<0.0f) std::swap(smallest, largest);
163     }
164 
computeRayIntersectionPoint(const osg::Vec3 & a,const osg::Vec3 & an,const osg::Vec3 & c,const osg::Vec3 & cn)165     osg::Vec3 computeRayIntersectionPoint(const osg::Vec3& a, const osg::Vec3& an, const osg::Vec3& c, const osg::Vec3& cn)
166     {
167         float denominator = ( cn.x() * an.y() - cn.y() * an.x());
168         if (denominator==0.0f)
169         {
170             //OSG_NOTICE<<"computeRayIntersectionPoint()<<denominator==0.0"<<std::endl;
171             // line segments must be parallel.
172             return (a+c)*0.5f;
173         }
174 
175         float t = ((a.x()-c.x())*an.y() - (a.y()-c.y())*an.x()) / denominator;
176         return c + cn*t;
177     }
178 
computeIntersectionPoint(const osg::Vec3 & a,const osg::Vec3 & b,const osg::Vec3 & c,const osg::Vec3 & d)179     osg::Vec3 computeIntersectionPoint(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d)
180     {
181         return computeRayIntersectionPoint(a, b-a, c, d-c);
182     }
183 
computeBisectorNormal(const osg::Vec3 & a,const osg::Vec3 & b,const osg::Vec3 & c,const osg::Vec3 & d)184     osg::Vec3 computeBisectorNormal(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d)
185     {
186         osg::Vec2 ab(a.x()-b.x(), a.y()-b.y());
187         osg::Vec2 dc(d.x()-c.x(), d.y()-c.y());
188         /*float length_ab =*/ ab.normalize();
189         /*float length_dc =*/ dc.normalize();
190 
191         float e = dc.y() - ab.y();
192         float f = ab.x() - dc.x();
193         float denominator = sqrtf(e*e + f*f);
194         float nx = e / denominator;
195         float ny = f / denominator;
196         if (( ab.x()*ny - ab.y()*nx) > 0.0f)
197         {
198             // OSG_NOTICE<<"   computeBisectorNormal(a=["<<a<<"], b=["<<b<<"], c=["<<c<<"], d=["<<d<<"]), nx="<<nx<<", ny="<<ny<<", denominator="<<denominator<<" no need to swap"<<std::endl;
199             return osg::Vec3(nx,ny,0.0f);
200         }
201         else
202         {
203             OSG_INFO<<"   computeBisectorNormal(a=["<<a<<"], b=["<<b<<"], c=["<<c<<"], d=["<<d<<"]), nx="<<nx<<", ny="<<ny<<", denominator="<<denominator<<" need to swap!!!"<<std::endl;
204             return osg::Vec3(-nx,-ny,0.0f);
205         }
206     }
207 
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)208     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)
209     {
210         osg::Vec3 intersection_abcd = computeIntersectionPoint(a,b,c,d);
211         osg::Vec3 bisector_abcd = computeBisectorNormal(a,b,c,d);
212         osg::Vec3 intersection_cdef = computeIntersectionPoint(c,d,e,f);
213         osg::Vec3 bisector_cdef = computeBisectorNormal(c,d,e,f);
214         if (bisector_abcd==bisector_cdef)
215         {
216             //OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
217             //OSG_NOTICE<<"   bisectors parallel, thickness = "<<FLT_MAX<<std::endl;
218             return FLT_MAX;
219         }
220 
221         osg::Vec3 bisector_intersection = computeRayIntersectionPoint(intersection_abcd,bisector_abcd, intersection_cdef, bisector_cdef);
222         osg::Vec3 normal(d.y()-c.y(), c.x()-d.x(), 0.0);
223         float cd_length = normal.normalize();
224         if (cd_length==0)
225         {
226             //OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
227             //OSG_NOTICE<<"   segment length==0, thickness = "<<FLT_MAX<<std::endl;
228             return FLT_MAX;
229         }
230 
231         float thickness = (bisector_intersection - c) * normal;
232     #if 0
233         OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
234         OSG_NOTICE<<"   bisector_abcd = "<<bisector_abcd<<", bisector_cdef="<<bisector_cdef<<std::endl;
235         OSG_NOTICE<<"   bisector_intersection = "<<bisector_intersection<<", thickness = "<<thickness<<std::endl;
236     #endif
237         return thickness;
238     }
239 
240 
computeThickness(unsigned int i)241     float computeThickness(unsigned int i)
242     {
243         Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ];
244         Segment& seg_target = _segments[ (i) % _segments.size() ];
245         Segment& seg_after =  _segments[ (i+1) % _segments.size() ];
246         return computeBisectorIntersectorThickness(
247             (*_vertices)[seg_before.first], (*_vertices)[seg_before.second],
248             (*_vertices)[seg_target.first], (*_vertices)[seg_target.second],
249             (*_vertices)[seg_after.first], (*_vertices)[seg_after.second]);
250     }
251 
252 
findMinThickness(unsigned int & minThickness_i,float & minThickness)253     bool findMinThickness(unsigned int& minThickness_i, float& minThickness)
254     {
255         minThickness_i = _segments.size();
256         for(unsigned int i=0; i<_segments.size(); ++i)
257         {
258             float thickness = computeThickness(i);
259             if (thickness>0.0 && thickness <  minThickness)
260             {
261                 minThickness = thickness;
262                 minThickness_i = i;
263             }
264         }
265 
266         return minThickness_i != _segments.size();
267     }
268 
removeAllSegmentsBelowThickness(float targetThickness)269     void removeAllSegmentsBelowThickness(float targetThickness)
270     {
271         // OSG_NOTICE<<"removeAllSegmentsBelowThickness("<<targetThickness<<")"<<std::endl;
272         for(;;)
273         {
274             unsigned int minThickness_i = _segments.size();
275             float minThickness = targetThickness;
276             if (!findMinThickness(minThickness_i,minThickness)) break;
277 
278             // OSG_NOTICE<<"  removing segment _segments["<<minThickness_i<<"] ("<<_segments[minThickness_i].first<<", "<<_segments[minThickness_i].second<<" with thickness="<<minThickness<<" "<<std::endl;
279             _segments.erase(_segments.begin()+minThickness_i);
280         }
281     }
282 
findMaxThickness(unsigned int & maxThickness_i,float & maxThickness)283     bool findMaxThickness(unsigned int& maxThickness_i, float& maxThickness)
284     {
285         maxThickness_i = _segments.size();
286         for(unsigned int i=0; i<_segments.size(); ++i)
287         {
288             float thickness = computeThickness(i);
289             if (thickness<0.0 && thickness >  maxThickness)
290             {
291                 maxThickness = thickness;
292                 maxThickness_i = i;
293             }
294         }
295 
296         return maxThickness_i != _segments.size();
297     }
298 
299 
removeAllSegmentsAboveThickness(float targetThickness)300     void removeAllSegmentsAboveThickness(float targetThickness)
301     {
302         // OSG_NOTICE<<"removeAllSegmentsBelowThickness("<<targetThickness<<")"<<std::endl;
303         for(;;)
304         {
305             unsigned int maxThickness_i = _segments.size();
306             float maxThickness = targetThickness;
307             if (!findMaxThickness(maxThickness_i,maxThickness)) break;
308 
309             // OSG_NOTICE<<"  removing segment _segments["<<minThickness_i<<"] ("<<_segments[minThickness_i].first<<", "<<_segments[minThickness_i].second<<" with thickness="<<minThickness<<" "<<std::endl;
310             _segments.erase(_segments.begin()+maxThickness_i);
311         }
312     }
313 
computeBisectorPoint(unsigned int i,float targetThickness,osg::Vec3 & va,osg::Vec3 & vb)314     float computeBisectorPoint(unsigned int i, float targetThickness, osg::Vec3& va, osg::Vec3& vb)
315     {
316         Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ];
317         Segment& seg_target = _segments[ (i) % _segments.size() ];
318         const osg::Vec3& a = (*_vertices)[seg_before.first];
319         const osg::Vec3& b = (*_vertices)[seg_before.second];
320         const osg::Vec3& c = (*_vertices)[seg_target.first];
321         const osg::Vec3& d = (*_vertices)[seg_target.second];
322         osg::Vec3 intersection_abcd = computeIntersectionPoint(a,b,c,d);
323         osg::Vec3 bisector_abcd = computeBisectorNormal(a,b,c,d);
324         osg::Vec3 ab_sidevector(b.y()-a.y(), a.x()-b.x(), 0.0);
325         ab_sidevector.normalize();
326         float scale_factor = 1.0/ (bisector_abcd*ab_sidevector);
327         float new_thickness = scale_factor*targetThickness;
328         osg::Vec3 new_vertex = intersection_abcd + bisector_abcd*new_thickness;
329 
330         //OSG_NOTICE<<"computeBisectorPoint("<<i<<", targetThickness="<<targetThickness<<", bisector_abcd = "<<bisector_abcd<<", ab_sidevector="<<ab_sidevector<<", b-a="<<b-a<<", scale_factor="<<scale_factor<<std::endl;
331 
332         va = intersection_abcd;
333         vb = new_vertex;
334 
335         return new_thickness;
336     }
337 
computeBisectorPoint(unsigned int i,osg::Vec3 & va,osg::Vec3 & vb)338     float computeBisectorPoint(unsigned int i, osg::Vec3& va, osg::Vec3& vb)
339     {
340         float tbefore = _segments[(i+_segments.size()-1)% _segments.size()].thickness;
341         float tafter = _segments[(i+_segments.size())% _segments.size()].thickness;
342         float t = tafter<0.0 ? osg::maximum(tbefore, tafter) : osg::minimum(tbefore, tafter);
343         return computeBisectorPoint(i, t, va, vb);
344     }
345 
computeThicknessThatBisectorAndSegmentMeet(const osg::Vec3 & va,const osg::Vec3 & vb,unsigned int bi,float original_thickness)346     float computeThicknessThatBisectorAndSegmentMeet(const osg::Vec3& va, const osg::Vec3& vb, unsigned int bi, float original_thickness)
347     {
348         osg::Vec3 bisector = (vb-va);
349 
350         bisector /= original_thickness;
351 
352         Segment& seg_opposite = _segments[ (bi+_segments.size()) % _segments.size() ];
353         const osg::Vec3& vc = (*_vertices)[seg_opposite.first];
354         const osg::Vec3& vd = (*_vertices)[seg_opposite.second];
355         osg::Vec3 cdn(vd.y()-vc.y(), vc.x()-vd.x(), 0.0);
356 
357         if (cdn.normalize()==0.0f) return false;
358 
359 
360         float denom = ( 1.0f - (bisector * cdn));
361         if (denom==0.0f)
362         {
363             return FLT_MAX;
364         }
365 
366         float h = ((va-vc)*cdn) / denom;
367         if (h<0.0)
368         {
369             return FLT_MAX;
370         }
371 
372         return h;
373     }
374 
clampSegmentToEdge(osg::Vec3 & va,osg::Vec3 & vb,const osg::Vec3 & vc,const osg::Vec3 & vd)375     int clampSegmentToEdge(osg::Vec3& va, osg::Vec3& vb, const osg::Vec3& vc, const osg::Vec3& vd)
376     {
377         osg::Vec2 ncd(vc.y()-vd.y(), vd.x()-vc.x());
378         float na = (va.x()-vc.x())*ncd.x() + (va.y()-vc.y())*ncd.y();
379         float nb = (vb.x()-vc.x())*ncd.x() + (vb.y()-vc.y())*ncd.y();
380 
381         if (na>=0.0f) // check if na is inside
382         {
383             // check if wholly inside
384             if (nb>=0.0f) return 1;
385 
386             // na is inside, nb outside, need to shift nb to (vc, vd) line.
387             float d = na-nb;
388 
389             if (d==0.0f)
390             {
391                 return 1;
392             }
393 
394             float r = na/d;
395             vb = va+(vb-va)*r;
396         }
397         else // na<0.0 and therefore outside
398         {
399             // check if wholly outside
400             if (nb<=0.0f) return -1;
401 
402             // na is outside, nb inside, need to shift na to (vc, vd) line.
403             float d = nb-na;
404             if (d==0.0f)
405             {
406                 return -1;
407             }
408 
409             float r = -na/d;
410 
411             va = va+(vb-va)*r;
412         }
413 
414         return 0;
415     }
416 
417 
doesSegmentIntersectQuad(osg::Vec3 va,osg::Vec3 vb,const osg::Vec3 & v1,const osg::Vec3 & v2,const osg::Vec3 & v3,const osg::Vec3 & v4)418     bool doesSegmentIntersectQuad(osg::Vec3 va, osg::Vec3 vb, const osg::Vec3& v1, const osg::Vec3& v2, const osg::Vec3& v3, const osg::Vec3& v4)
419     {
420         osg::Vec2 ncd(v1.y()-v2.y(), v2.x()-v1.x());
421 
422         // catch case of bisector boundary point being behind the segment of interest
423         float na = (va.x()-v1.x())*ncd.x() + (va.y()-v1.y())*ncd.y();
424         if (na>=0.0) return false;
425 
426         // catch case of bisector pointing away from the segment of interest
427         float nb = (vb.x()-v1.x())*ncd.x() + (vb.y()-v1.y())*ncd.y();
428         if (na>=nb) return false;
429 
430         osg::Vec3 cp123 = (v2-v1)^(v3-v2);
431         osg::Vec3 cp234 = (v3-v2)^(v4-v3);
432         float dot_1234 = cp123*cp234;
433         bool not_crossed_over = (dot_1234>=0.0);
434 
435         if (clampSegmentToEdge(va, vb, v1, v4)<0) return false;
436         if (clampSegmentToEdge(va, vb, v3, v2)<0) return false;
437         if (clampSegmentToEdge(va, vb, v2, v1)<0) return false;
438         if (not_crossed_over && clampSegmentToEdge(va, vb, v4, v3)<0) return false;
439 
440         return true;
441     }
442 
checkBisectorAgainstBoundary(osg::Vec3 va,osg::Vec3 vb,float original_thickness)443     float checkBisectorAgainstBoundary(osg::Vec3 va, osg::Vec3 vb, float original_thickness)
444     {
445         float thickness = original_thickness;
446 
447         osg::Vec3 before_outer, before_inner;
448         osg::Vec3 after_outer, after_inner;
449 
450         for(unsigned int i=0; i<_segments.size(); ++i)
451         {
452             Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ];
453             Segment& seg_target = _segments[ (i) % _segments.size() ];
454             Segment& seg_after = _segments[ (i+1) % _segments.size() ];
455 
456             computeBisectorPoint(i, before_outer, before_inner);
457             computeBisectorPoint(i+1, after_outer, after_inner);
458 
459             if (doesSegmentIntersectQuad(va, vb, before_outer, after_outer, after_inner, before_inner))
460             {
461                 float new_thickness = computeThicknessThatBisectorAndSegmentMeet(va, vb, i, original_thickness);
462 
463                 shorten(thickness, new_thickness);
464                 shorten(seg_before.suggestedThickness, new_thickness);
465                 shorten(seg_target.suggestedThickness, new_thickness);
466                 shorten(seg_after.suggestedThickness, new_thickness);
467             }
468 
469         }
470         return thickness;
471     }
472 
checkBoundaries(Boundary & boundary)473     void checkBoundaries(Boundary& boundary)
474     {
475         osg::Vec3 va, vb;
476         float min_thickiness = FLT_MAX;
477         for(unsigned int i=0; i<boundary._segments.size(); ++i)
478         {
479             boundary.computeBisectorPoint(i, va, vb);
480             float new_thickness = checkBisectorAgainstBoundary(va, vb, boundary._segments[i].thickness);
481             if (boundary.shortenBisector(i, new_thickness))
482             {
483                 shorten (min_thickiness, new_thickness);
484             }
485 
486         }
487     }
488 
addBoundaryToGeometry(osg::Geometry * geometry,float,const std::string & faceName,const std::string & bevelName)489     void addBoundaryToGeometry(osg::Geometry* geometry, float /*targetThickness*/, const std::string& faceName, const std::string& bevelName)
490     {
491         if (_segments.empty()) return;
492 
493         unsigned int start = (*_elements)[0];
494         unsigned int count = _elements->size();
495 
496         osg::Vec3Array* new_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
497         if (!new_vertices)
498         {
499             new_vertices = new osg::Vec3Array(*_vertices);
500             geometry->setVertexArray(new_vertices);
501         }
502 
503         // allocate the primitive set to store the face geometry
504         osg::ref_ptr<osg::DrawElementsUShort> face = new osg::DrawElementsUShort(GL_POLYGON);
505         face->setName(faceName);
506 
507         // reserve enough space in the vertex array to accommodate the vertices associated with the segments
508         new_vertices->reserve(new_vertices->size() + _segments.size()+1 + count);
509 
510         // create vertices
511         unsigned int previous_second = _segments[0].second;
512 
513         osg::Vec3 boundaryPoint, newPoint;
514         computeBisectorPoint(0, boundaryPoint, newPoint);
515 
516         unsigned int first = new_vertices->size();
517         new_vertices->push_back(newPoint);
518 
519         if (_segments[0].first != start)
520         {
521             //OSG_NOTICE<<"We have pruned from the start"<<std::endl;
522             for(unsigned int j=start; j<=_segments[0].first;++j)
523             {
524                 face->push_back(first);
525             }
526         }
527         else
528         {
529             face->push_back(first);
530         }
531 
532 
533         for(unsigned int i=1; i<_segments.size(); ++i)
534         {
535 
536             computeBisectorPoint(i, boundaryPoint, newPoint);
537 
538             unsigned int vi = new_vertices->size();
539             new_vertices->push_back(newPoint);
540 
541             if (previous_second != _segments[i].first)
542             {
543                 //OSG_NOTICE<<"Gap in boundary"<<previous_second<<" to "<<_segments[i].first<<std::endl;
544                 for(unsigned int j=previous_second; j<=_segments[i].first;++j)
545                 {
546                     face->push_back(vi);
547                 }
548             }
549             else
550             {
551                 face->push_back(vi);
552             }
553 
554             previous_second = _segments[i].second;
555         }
556 
557         // fill the end of the polygon with repititions of the first index in the polygon to ensure
558         // that the original and new boundary polygons have the same number and pairing of indices.
559         // This ensures that the bevel can be created coherently.
560         while(face->size() < count)
561         {
562             face->push_back(first);
563         }
564 
565         if (!faceName.empty())
566         {
567             // add face primitive set for polygon
568             geometry->addPrimitiveSet(face.get());
569         }
570 
571         osg::DrawElementsUShort* bevel = new osg::DrawElementsUShort(GL_QUAD_STRIP);
572         bevel->setName(bevelName);
573         bevel->reserve(count*2);
574         for(unsigned int i=0; i<count; ++i)
575         {
576             bevel->push_back((*_elements)[i]);
577             bevel->push_back((*face)[i]);
578         }
579         geometry->addPrimitiveSet(bevel);
580     }
581 
582 protected:
583 
~Boundary()584     virtual ~Boundary() {}
585 };
586 
587 
588 /////////////////////////////////////////////////////////////////////////////////////////
589 //
590 // computeGlyphGeometry
591 //
592 struct CollectTriangleIndicesFunctor
593 {
CollectTriangleIndicesFunctorosgText::CollectTriangleIndicesFunctor594     CollectTriangleIndicesFunctor() {}
595 
596     typedef std::vector<unsigned int> Indices;
597     Indices _indices;
598 
operator ()osgText::CollectTriangleIndicesFunctor599     void operator() (unsigned int p1, unsigned int p2, unsigned int p3)
600     {
601         if (p1==p2 || p2==p3 || p1==p3)
602         {
603             return;
604         }
605 
606         _indices.push_back(p1);
607         _indices.push_back(p3);
608         _indices.push_back(p2);
609 
610     }
611 };
612 
613 
614 
computeGlyphGeometry(const osgText::Glyph3D * glyph,const Bevel & bevel,float shellThickness)615 OSGTEXT_EXPORT osg::Geometry* computeGlyphGeometry(const osgText::Glyph3D* glyph, const Bevel& bevel, float shellThickness)
616 {
617 #if REPORT_TIME
618     osg::ElapsedTime timer;
619 #endif
620 
621     float bevelThickness = bevel.getBevelThickness();
622     bool roundedWebs = bevel.getSmoothConcaveJunctions();
623 
624 
625     const osg::Vec3Array* source_vertices = glyph->getRawVertexArray();
626     const osg::Geometry::PrimitiveSetList& source_primitives = glyph->getRawFacePrimitiveSetList();
627 
628     if (!source_vertices) return NULL;
629     if (source_primitives.empty()) return NULL;
630 
631 #if 0
632     {
633         osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
634         geom->setVertexArray(const_cast<osg::Vec3Array*>(source_vertices));
635         geom->setPrimitiveSetList(source_primitives);
636 
637         osgDB::writeNodeFile(*geom, "test.osgt");
638     }
639 #endif
640 
641 
642     osg::ref_ptr<osg::Vec3Array> orig_vertices = new osg::Vec3Array;
643     osg::Geometry::PrimitiveSetList orig_primitives;
644 
645     orig_vertices->reserve(source_vertices->size());
646     orig_primitives.reserve(source_primitives.size());
647 
648     typedef std::vector<int> Indices;
649     Indices remappedIndices(source_vertices->size(), -1);
650 
651     float convexCornerInsertionWidth = 0.02;
652     float convexCornerCutoffAngle = osg::inDegrees(45.0f);
653 
654     int num_vertices_on_web = 10;
655 
656 
657     for(osg::Geometry::PrimitiveSetList::const_iterator itr = source_primitives.begin();
658         itr != source_primitives.end();
659         ++itr)
660     {
661         const osg::DrawElementsUShort* elements = dynamic_cast<const osg::DrawElementsUShort*>(itr->get());
662         if (elements && elements->size()>2)
663         {
664             osg::ref_ptr<osg::DrawElementsUShort> new_elements = new osg::DrawElementsUShort(elements->getMode());
665             orig_primitives.push_back(new_elements.get());
666 
667             int num_indices = elements->size();
668             for(int ei = 0; ei<num_indices-1; ++ei)
669             {
670                 int vi_before = (ei==0) ? (*elements)[(elements->size()-2)] : (*elements)[ei-1];
671                 int vi_curr = (*elements)[ei];
672                 int vi_after = (*elements)[ei+1];
673 
674                 osg::Vec3 va = (*source_vertices)[vi_before];
675                 osg::Vec3 vb = (*source_vertices)[vi_curr];
676                 osg::Vec3 vc = (*source_vertices)[vi_after];
677 
678                 // OSG_NOTICE<<"   "<<vi_before<<", "<<vi_curr<<", "<<vi_after<<std::endl;
679 
680                 if (vi_curr>=static_cast<int>(remappedIndices.size())) remappedIndices.resize(vi_curr+1,-1);
681 
682                 int new_index = remappedIndices[vi_curr];
683                 if (new_index<0)
684                 {
685                     remappedIndices[vi_curr] = new_index = orig_vertices->size();
686                     orig_vertices->push_back(vb);
687                 }
688                 new_elements->push_back(new_index);
689 
690                 if (roundedWebs)
691                 {
692                     osg::Vec3 vab = vb-va;
693                     osg::Vec3 vbc = vc-vb;
694                     float len_vab = vab.normalize();
695                     float len_vbc = vbc.normalize();
696 
697                     if (len_vab*len_vbc==0.0f)
698                     {
699                         OSG_NOTICE<<"Warning: len_vab="<<len_vab<<", len_vbc="<<len_vbc<<std::endl;
700                         continue;
701                     }
702 
703                     osg::Vec3 cross = vab ^ vbc;
704                     if (cross.z()>0.0)
705                     {
706                         float dot = vab * vbc;
707 
708                         float theta = atan2(cross.z(), dot);
709 
710                         // OSG_NOTICE<<"  convex segment  vab=("<<vab<<") vbc=("<<vbc<<") theta"<<osg::RadiansToDegrees(theta)<<std::endl;
711 
712                         if (theta>convexCornerCutoffAngle)
713                         {
714                             vab.normalize();
715                             vbc.normalize();
716 
717                             float min_len = osg::minimum(len_vab, len_vbc);
718 
719                             osg::Vec3 v_before = vb - vab*(min_len*convexCornerInsertionWidth);
720                             osg::Vec3 v_after = vb + vbc*(min_len*convexCornerInsertionWidth);
721                             osg::Vec3 v_mid = v_before + (v_after-v_before)*0.5f;
722 
723                             float h = (vb-v_mid).length();
724                             float w = (v_after-v_before).length()*0.5f;
725                             float l = w*w / h;
726                             float r = sqrt(l*l + w*w);
727                             float alpha = atan2(w,h);
728                             float beta = osg::PI-alpha*2.0f;
729 
730                             // OSG_NOTICE<<"    h = "<<h<<", w = "<<w<<", l = "<<l<<", r="<<r<<", alpha="<<osg::RadiansToDegrees(alpha)<<", beta="<<osg::RadiansToDegrees(beta)<<std::endl;
731 
732                             osg::Vec3 vertical = (vb-v_mid)*(1.0f/h);
733                             osg::Vec3 horizontal = (v_after-v_before)*(r/(w*2.0f));
734 
735                             vertical.normalize();
736 
737                             osg::Vec3 v_center = v_mid-vertical*l;
738                             vertical *= r;
739 
740                             (*orig_vertices)[new_index] = v_before;
741 
742                             for(int i=1; i<=num_vertices_on_web-1; ++i)
743                             {
744                                 float gamma = ((static_cast<float>(i)/static_cast<float>(num_vertices_on_web))-0.5f) * beta;
745                                 // OSG_NOTICE<<"     gamma = "<<osg::RadiansToDegrees(gamma)<<" sin(gamma)="<<sin(gamma)<<", cos(gamma)="<<cos(gamma)<<std::endl;
746 
747                                 osg::Vec3 v = v_center + horizontal*sin(gamma) + vertical*cos(gamma);
748 
749                                 new_elements->push_back(orig_vertices->size());
750                                 orig_vertices->push_back(v);
751                             }
752                             new_elements->push_back(orig_vertices->size());
753                             orig_vertices->push_back(v_after);
754                         }
755                     }
756                 }
757             }
758 
759             // add the first element to create the loop.
760             new_elements->push_back(new_elements->front());
761 
762         }
763 
764     }
765 
766     if (!orig_vertices) return 0;
767     if (orig_primitives.empty()) return 0;
768 
769 
770 
771     osg::ref_ptr<osg::Geometry> new_geometry = new osg::Geometry;
772 
773 #define HANDLE_SHELL 0
774 
775 
776     typedef std::vector< osg::ref_ptr<Boundary> > Boundaries;
777     Boundaries innerBoundaries;
778     Boundaries outerBoundaries;
779 
780     for(osg::Geometry::PrimitiveSetList::const_iterator itr = orig_primitives.begin();
781         itr != orig_primitives.end();
782         ++itr)
783     {
784         if ((*itr)->getMode()==GL_POLYGON)
785         {
786             osg::ref_ptr<Boundary> boundaryInner = new Boundary(orig_vertices.get(), itr->get(), bevelThickness);
787             //boundaryInner->removeAllSegmentsBelowThickness(bevelThickness);
788             innerBoundaries.push_back(boundaryInner.get());
789 #if HANDLE_SHELL
790             osg::ref_ptr<Boundary> boundaryOuter = new Boundary(orig_vertices.get(), itr->get(), -shellThickness);
791             boundaryOuter->removeAllSegmentsAboveThickness(-shellThickness);
792             outerBoundaries.push_back(boundaryOuter.get());
793 #endif
794         }
795     }
796 
797     OSG_INFO<<"Handling bevel"<<std::endl;
798     for(unsigned int i=0; i<innerBoundaries.size(); ++i)
799     {
800         for(unsigned int j=0; j<innerBoundaries.size(); ++j)
801         {
802             innerBoundaries[i]->checkBoundaries(*innerBoundaries[j]);
803         }
804     }
805 
806     float smallest = FLT_MAX, largest = -FLT_MAX;
807     for(unsigned int i=0; i<innerBoundaries.size(); ++i)
808     {
809         innerBoundaries[i]->getSuggestedThicknessRange(smallest, largest);
810     }
811 
812     OSG_INFO<<"Smallest = "<<smallest<<std::endl;
813     OSG_INFO<<"Largest = "<<largest<<std::endl;
814 
815     float targetThickness = largest*0.75f;
816 
817 #if 1
818     for(unsigned int i=0; i<innerBoundaries.size(); ++i)
819     {
820         innerBoundaries[i]->applyThickness(targetThickness);
821     }
822 
823     for(Boundaries::iterator itr = innerBoundaries.begin();
824         itr != innerBoundaries.end();
825         ++itr)
826     {
827         (*itr)->removeAllSegmentsBelowThickness(targetThickness*0.75f);
828     }
829 
830 #if 1
831     for(unsigned int i=0; i<innerBoundaries.size(); ++i)
832     {
833         for(unsigned int j=0; j<innerBoundaries.size(); ++j)
834         {
835             innerBoundaries[i]->checkBoundaries(*innerBoundaries[j]);
836         }
837     }
838 #endif
839 #endif
840 
841     for(Boundaries::iterator itr = innerBoundaries.begin();
842         itr != innerBoundaries.end();
843         ++itr)
844     {
845         (*itr)->applySuggestedThickness();
846         (*itr)->addBoundaryToGeometry(new_geometry.get(), bevelThickness, "face", "bevel");
847     }
848 
849     OSG_INFO<<"Handling shell"<<std::endl;
850     for(unsigned int i=0; i<outerBoundaries.size(); ++i)
851     {
852         for(unsigned int j=0; j<outerBoundaries.size(); ++j)
853         {
854             outerBoundaries[i]->checkBoundaries(*outerBoundaries[j]);
855         }
856     }
857 
858     for(Boundaries::iterator itr = outerBoundaries.begin();
859         itr != outerBoundaries.end();
860         ++itr)
861     {
862         (*itr)->applySuggestedThickness();
863         (*itr)->addBoundaryToGeometry(new_geometry.get(), -shellThickness, "", "shell");
864     }
865 
866 
867 
868 
869     osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(new_geometry->getVertexArray());
870 
871     // need to tessellate the inner boundary
872     {
873         osg::ref_ptr<osg::Geometry> face_geometry = new osg::Geometry;
874         face_geometry->setVertexArray(vertices);
875 
876         osg::CopyOp copyop(osg::CopyOp::DEEP_COPY_ALL);
877 
878         osg::Geometry::PrimitiveSetList primitiveSets;
879 
880         for(osg::Geometry::PrimitiveSetList::iterator itr = new_geometry->getPrimitiveSetList().begin();
881             itr != new_geometry->getPrimitiveSetList().end();
882             ++itr)
883         {
884             osg::PrimitiveSet* prim = itr->get();
885             if (prim->getName()=="face")  face_geometry->addPrimitiveSet(copyop(itr->get()));
886             else primitiveSets.push_back(prim);
887         }
888 
889         osgUtil::Tessellator ts;
890         ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
891         ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
892         ts.retessellatePolygons(*face_geometry);
893 
894         osg::TriangleIndexFunctor<CollectTriangleIndicesFunctor> ctif;
895         face_geometry->accept(ctif);
896         CollectTriangleIndicesFunctor::Indices& indices = ctif._indices;
897 
898         // remove the previous primitive sets
899         new_geometry->getPrimitiveSetList().clear();
900 
901         // create a front face using triangle indices
902         osg::DrawElementsUShort* front_face = new osg::DrawElementsUShort(GL_TRIANGLES);
903         front_face->setName("face");
904         new_geometry->addPrimitiveSet(front_face);
905         for(unsigned int i=0; i<indices.size();++i)
906         {
907             front_face->push_back(indices[i]);
908         }
909 
910         for(osg::Geometry::PrimitiveSetList::iterator itr = primitiveSets.begin();
911             itr != primitiveSets.end();
912             ++itr)
913         {
914             osg::PrimitiveSet* prim = itr->get();
915             if (prim->getName()!="face")  new_geometry->addPrimitiveSet(prim);
916         }
917     }
918 
919 #if REPORT_TIME
920     OSG_NOTICE<<"Time to compute 3d glyp geometry: "<<timer.elapsedTime_m()<<"ms"<<std::endl;
921 #endif
922 
923     return new_geometry.release();
924 }
925 
926 /////////////////////////////////////////////////////////////////////////////////////////
927 //
928 // computeTextGeometry
929 //
computeTextGeometry(const osgText::Glyph3D * glyph,float width)930 OSGTEXT_EXPORT osg::Geometry* computeTextGeometry(const osgText::Glyph3D* glyph, float width)
931 {
932     const osg::Vec3Array* orig_vertices = glyph->getRawVertexArray();
933     const osg::Geometry::PrimitiveSetList& orig_primitives = glyph->getRawFacePrimitiveSetList();
934 
935     osg::ref_ptr<osg::Geometry> text_geometry = new osg::Geometry;
936     osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array((*orig_vertices));
937 
938     text_geometry->setVertexArray(vertices.get());
939     text_geometry->setPrimitiveSetList(orig_primitives);
940 
941     osgUtil::Tessellator ts;
942     ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
943     ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
944     ts.retessellatePolygons(*text_geometry);
945 
946     osg::TriangleIndexFunctor<CollectTriangleIndicesFunctor> ctif;
947     text_geometry->accept(ctif);
948     CollectTriangleIndicesFunctor::Indices& indices = ctif._indices;
949 
950     // remove the previous primitive sets
951     text_geometry->getPrimitiveSetList().clear();
952 
953     if (indices.empty()) return 0;
954 
955 
956     // create a front face using triangle indices
957     osg::DrawElementsUShort* frontFace = new osg::DrawElementsUShort(GL_TRIANGLES);
958     frontFace->setName("front");
959     text_geometry->addPrimitiveSet(frontFace);
960     for(unsigned int i=0; i<indices.size();++i)
961     {
962         frontFace->push_back(indices[i]);
963     }
964 
965     typedef std::vector<unsigned int> Indices;
966     const unsigned int NULL_VALUE = UINT_MAX;
967     Indices back_indices;
968     back_indices.resize(vertices->size(), NULL_VALUE);
969     osg::Vec3 forward(0,0,-width);
970 
971     // build up the vertices primitives for the back face, and record the indices
972     // for later use, and to ensure sharing of vertices in the face primitive set
973     // the order of the triangle indices are flipped to make sure that the triangles are back face
974     osg::DrawElementsUShort* backFace = new osg::DrawElementsUShort(GL_TRIANGLES);
975     backFace->setName("back");
976     text_geometry->addPrimitiveSet(backFace);
977     for(unsigned int i=0; i<indices.size()-2;)
978     {
979         unsigned int p1 = indices[i++];
980         unsigned int p2 = indices[i++];
981         unsigned int p3 = indices[i++];
982         if (back_indices[p1]==NULL_VALUE)
983         {
984             back_indices[p1] = vertices->size();
985             vertices->push_back((*vertices)[p1]+forward);
986         }
987 
988         if (back_indices[p2]==NULL_VALUE)
989         {
990             back_indices[p2] = vertices->size();
991             vertices->push_back((*vertices)[p2]+forward);
992         }
993 
994         if (back_indices[p3]==NULL_VALUE)
995         {
996             back_indices[p3] = vertices->size();
997             vertices->push_back((*vertices)[p3]+forward);
998         }
999 
1000         backFace->push_back(back_indices[p1]);
1001         backFace->push_back(back_indices[p3]);
1002         backFace->push_back(back_indices[p2]);
1003     }
1004 
1005     unsigned int orig_size = orig_vertices->size();
1006     Indices frontedge_indices, backedge_indices;
1007     frontedge_indices.resize(orig_size, NULL_VALUE);
1008     backedge_indices.resize(orig_size, NULL_VALUE);
1009 
1010 
1011     for(osg::Geometry::PrimitiveSetList::const_iterator itr = orig_primitives.begin();
1012         itr != orig_primitives.end();
1013         ++itr)
1014     {
1015         osg::DrawElementsUShort* edging = new osg::DrawElementsUShort(osg::PrimitiveSet::QUAD_STRIP);
1016         edging->setName("wall");
1017         text_geometry->addPrimitiveSet(edging);
1018 
1019         osg::DrawElementsUShort* elements = dynamic_cast<osg::DrawElementsUShort*>(itr->get());
1020         if (elements)
1021         {
1022             for(unsigned int i=0; i<elements->size(); ++i)
1023             {
1024                 unsigned int ei = (*elements)[i];
1025                 if (frontedge_indices[ei]==NULL_VALUE)
1026                 {
1027                     frontedge_indices[ei] = vertices->size();
1028                     vertices->push_back((*orig_vertices)[ei]);
1029                 }
1030                 if (backedge_indices[ei]==NULL_VALUE)
1031                 {
1032                     backedge_indices[ei] = vertices->size();
1033                     vertices->push_back((*orig_vertices)[ei]+forward);
1034                 }
1035 
1036                 edging->push_back(backedge_indices[ei]);
1037                 edging->push_back(frontedge_indices[ei]);
1038             }
1039         }
1040     }
1041 
1042     return text_geometry.release();
1043 }
1044 
1045 /////////////////////////////////////////////////////////////////////////////////////////
1046 //
1047 // computeTextGeometry
1048 //
computeTextGeometry(osg::Geometry * glyphGeometry,const osgText::Bevel & profile,float width)1049 OSGTEXT_EXPORT osg::Geometry* computeTextGeometry(osg::Geometry* glyphGeometry, const osgText::Bevel& profile, float width)
1050 {
1051     if (!glyphGeometry)
1052     {
1053         OSG_NOTICE<<"Warning: computeTextGeometry(..) error, glyphGeometry="<<glyphGeometry<<std::endl;
1054         return 0;
1055     }
1056 
1057     osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(glyphGeometry->getVertexArray());
1058     if (!orig_vertices)
1059     {
1060         OSG_INFO<<"Warning: computeTextGeometry(..): No vertices on glyphGeometry."<<std::endl;
1061         return 0;
1062     }
1063 
1064     osg::ref_ptr<osg::Geometry> text_geometry = new osg::Geometry;
1065     osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
1066     text_geometry->setVertexArray(vertices.get());
1067 
1068     typedef std::vector<unsigned int> Indices;
1069     const unsigned int NULL_VALUE = UINT_MAX;
1070     Indices front_indices, back_indices;
1071     front_indices.resize(orig_vertices->size(), NULL_VALUE);
1072     back_indices.resize(orig_vertices->size(), NULL_VALUE);
1073 
1074     osg::DrawElementsUShort* face = 0;
1075     osg::Geometry::PrimitiveSetList bevelPrimitiveSets;
1076     osg::Vec3 forward(0,0,-width);
1077 
1078     // collect bevels and face primitive sets
1079     for(osg::Geometry::PrimitiveSetList::iterator itr = glyphGeometry->getPrimitiveSetList().begin();
1080         itr != glyphGeometry->getPrimitiveSetList().end();
1081         ++itr)
1082     {
1083         osg::PrimitiveSet* prim = itr->get();
1084         if (prim->getName()=="face") face = dynamic_cast<osg::DrawElementsUShort*>(prim);
1085         else if (prim->getName()=="bevel") bevelPrimitiveSets.push_back(prim);
1086     }
1087 
1088     // if we don't have a face we can't create any 3d text
1089     if (!face) return 0;
1090 
1091     // face doesn't have enough vertices on it to represent a polygon.
1092     if (face->size()<3)
1093     {
1094         OSG_NOTICE<<"Face does not have enough elements to be able to represent a polygon, face->size() = "<<face->size()<<std::endl;
1095         return 0;
1096     }
1097 
1098     // build up the vertices primitives for the front face, and record the indices
1099     // for later use, and to ensure sharing of vertices in the face primitive set
1100     osg::DrawElementsUShort* frontFace = new osg::DrawElementsUShort(GL_TRIANGLES);
1101     frontFace->setName("front");
1102     text_geometry->addPrimitiveSet(frontFace);
1103     for(unsigned int i=0; i<face->size();)
1104     {
1105         unsigned int pi = (*face)[i++];
1106         if (front_indices[pi]==NULL_VALUE)
1107         {
1108             front_indices[pi] = vertices->size();
1109             vertices->push_back((*orig_vertices)[pi]);
1110         }
1111         frontFace->push_back(front_indices[pi]);
1112     }
1113 
1114 
1115     // build up the vertices primitives for the back face, and record the indices
1116     // for later use, and to ensure sharing of vertices in the face primitive set
1117     // the order of the triangle indices are flipped to make sure that the triangles are back face
1118     osg::DrawElementsUShort* backFace = new osg::DrawElementsUShort(GL_TRIANGLES);
1119     backFace->setName("back");
1120     text_geometry->addPrimitiveSet(backFace);
1121     for(unsigned int i=0; i<face->size()-2;)
1122     {
1123         unsigned int p1 = (*face)[i++];
1124         unsigned int p2 = (*face)[i++];
1125         unsigned int p3 = (*face)[i++];
1126         if (back_indices[p1]==NULL_VALUE)
1127         {
1128             back_indices[p1] = vertices->size();
1129             vertices->push_back((*orig_vertices)[p1]+forward);
1130         }
1131 
1132         if (back_indices[p2]==NULL_VALUE)
1133         {
1134             back_indices[p2] = vertices->size();
1135             vertices->push_back((*orig_vertices)[p2]+forward);
1136         }
1137 
1138         if (back_indices[p3]==NULL_VALUE)
1139         {
1140             back_indices[p3] = vertices->size();
1141             vertices->push_back((*orig_vertices)[p3]+forward);
1142         }
1143 
1144         backFace->push_back(back_indices[p1]);
1145         backFace->push_back(back_indices[p3]);
1146         backFace->push_back(back_indices[p2]);
1147     }
1148 
1149     // now build up the bevel
1150     for(osg::Geometry::PrimitiveSetList::iterator itr = bevelPrimitiveSets.begin();
1151         itr != bevelPrimitiveSets.end();
1152         ++itr)
1153     {
1154         osg::DrawElementsUShort* bevel = dynamic_cast<osg::DrawElementsUShort*>(itr->get());
1155         if (!bevel) continue;
1156 
1157         unsigned int no_vertices_on_boundary = bevel->size()/2;
1158 
1159         const osgText::Bevel::Vertices& profileVertices = profile.getVertices();
1160         unsigned int no_vertices_on_bevel = profileVertices.size();
1161 
1162         Indices bevelIndices;
1163         bevelIndices.resize(no_vertices_on_boundary*no_vertices_on_bevel, NULL_VALUE);
1164 
1165         // populate vertices
1166         for(unsigned int i=0; i<no_vertices_on_boundary; ++i)
1167         {
1168             unsigned int topi = (*bevel)[i*2];
1169             unsigned int basei = (*bevel)[i*2+1];
1170 
1171             osg::Vec3& top_vertex = (*orig_vertices)[ topi ];
1172             osg::Vec3& base_vertex = (*orig_vertices)[ basei ];
1173             osg::Vec3 up = top_vertex-base_vertex;
1174 
1175             if (front_indices[basei]==NULL_VALUE)
1176             {
1177                 front_indices[basei] = vertices->size();
1178                 vertices->push_back(base_vertex);
1179             }
1180 
1181             bevelIndices[i*no_vertices_on_bevel + 0] = front_indices[basei];
1182 
1183             for(unsigned int j=1; j<no_vertices_on_bevel-1; ++j)
1184             {
1185                 const osg::Vec2& pv = profileVertices[j];
1186                 osg::Vec3 pos( base_vertex + (forward * pv.x()) + (up * pv.y()) );
1187                 bevelIndices[i*no_vertices_on_bevel + j] = vertices->size();
1188                 vertices->push_back(pos);
1189             }
1190 
1191             if (back_indices[basei]==NULL_VALUE)
1192             {
1193                 back_indices[basei] = vertices->size();
1194                 vertices->push_back(base_vertex + forward);
1195             }
1196 
1197             bevelIndices[i*no_vertices_on_bevel + no_vertices_on_bevel-1] = back_indices[basei];
1198         }
1199 
1200         osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(GL_TRIANGLES);
1201         elements->setName("wall");
1202         unsigned int base, next;
1203         for(unsigned int i = 0; i< no_vertices_on_boundary-1; ++i)
1204         {
1205             for(unsigned int j=0; j<no_vertices_on_bevel-1; ++j)
1206             {
1207                 base = i*no_vertices_on_bevel + j;
1208                 next = base + no_vertices_on_bevel;
1209 
1210                 elements->push_back(bevelIndices[base]);
1211                 elements->push_back(bevelIndices[next]);
1212                 elements->push_back(bevelIndices[base+1]);
1213 
1214                 elements->push_back(bevelIndices[base+1]);
1215                 elements->push_back(bevelIndices[next]);
1216                 elements->push_back(bevelIndices[next+1]);
1217             }
1218         }
1219 
1220         text_geometry->addPrimitiveSet(elements);
1221     }
1222 
1223     return text_geometry.release();
1224 }
1225 
1226 /////////////////////////////////////////////////////////////////////////////////////////
1227 //
1228 // computeShellGeometry
1229 //
computeShellGeometry(osg::Geometry * glyphGeometry,const osgText::Bevel & profile,float width)1230 OSGTEXT_EXPORT osg::Geometry* computeShellGeometry(osg::Geometry* glyphGeometry, const osgText::Bevel& profile, float width)
1231 {
1232     if (!glyphGeometry)
1233     {
1234         OSG_NOTICE<<"Warning: computeShellGeometry(..) error, glyphGeometry="<<glyphGeometry<<std::endl;
1235         return 0;
1236     }
1237 
1238     osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(glyphGeometry->getVertexArray());
1239     if (!orig_vertices)
1240     {
1241         OSG_NOTICE<<"computeTextGeometry(..): No vertices on glyphGeometry."<<std::endl;
1242         return 0;
1243     }
1244 
1245     osg::ref_ptr<osg::Geometry> text_geometry = new osg::Geometry;
1246     osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
1247     text_geometry->setVertexArray(vertices.get());
1248 
1249     typedef std::vector<unsigned int> Indices;
1250     const unsigned int NULL_VALUE = UINT_MAX;
1251     Indices front_indices, back_indices;
1252     front_indices.resize(orig_vertices->size(), NULL_VALUE);
1253     back_indices.resize(orig_vertices->size(), NULL_VALUE);
1254 
1255     osg::DrawElementsUShort* face = 0;
1256     osg::Geometry::PrimitiveSetList bevelPrimitiveSets;
1257     osg::Geometry::PrimitiveSetList shellPrimitiveSets;
1258     osg::Vec3 frontOffset(0,0,width);
1259     osg::Vec3 backOffset(0,0,-2.0*width);
1260     osg::Vec3 forward(backOffset-frontOffset);
1261 
1262     // collect bevels and face primitive sets
1263     for(osg::Geometry::PrimitiveSetList::iterator itr = glyphGeometry->getPrimitiveSetList().begin();
1264         itr != glyphGeometry->getPrimitiveSetList().end();
1265         ++itr)
1266     {
1267         osg::PrimitiveSet* prim = itr->get();
1268         if (prim->getName()=="face") face = dynamic_cast<osg::DrawElementsUShort*>(prim);
1269         else if (prim->getName()=="bevel") bevelPrimitiveSets.push_back(prim);
1270         else if (prim->getName()=="shell") shellPrimitiveSets.push_back(prim);
1271     }
1272 
1273     // if we don't have a face we can't create any 3d text
1274     if (!face) return 0;
1275 
1276     // build up the vertices primitives for the front face, and record the indices
1277     // for later use, and to ensure sharing of vertices in the face primitive set
1278     // the order of the triangle indices are flipped to make sure that the triangles are back face
1279     osg::DrawElementsUShort* frontFace = new osg::DrawElementsUShort(GL_TRIANGLES);
1280     text_geometry->addPrimitiveSet(frontFace);
1281     for(unsigned int i=0; i<face->size()-2;)
1282     {
1283         unsigned int p1 = (*face)[i++];
1284         unsigned int p2 = (*face)[i++];
1285         unsigned int p3 = (*face)[i++];
1286         if (front_indices[p1]==NULL_VALUE)
1287         {
1288             front_indices[p1] = vertices->size();
1289             vertices->push_back((*orig_vertices)[p1]+frontOffset);
1290         }
1291 
1292         if (front_indices[p2]==NULL_VALUE)
1293         {
1294             front_indices[p2] = vertices->size();
1295             vertices->push_back((*orig_vertices)[p2]+frontOffset);
1296         }
1297 
1298         if (front_indices[p3]==NULL_VALUE)
1299         {
1300             front_indices[p3] = vertices->size();
1301             vertices->push_back((*orig_vertices)[p3]+frontOffset);
1302         }
1303 
1304         frontFace->push_back(front_indices[p1]);
1305         frontFace->push_back(front_indices[p3]);
1306         frontFace->push_back(front_indices[p2]);
1307     }
1308 
1309 
1310     // build up the vertices primitives for the back face, and record the indices
1311     // for later use, and to ensure sharing of vertices in the face primitive set
1312     osg::DrawElementsUShort* backFace = new osg::DrawElementsUShort(GL_TRIANGLES);
1313     text_geometry->addPrimitiveSet(backFace);
1314     for(unsigned int i=0; i<face->size();)
1315     {
1316         unsigned int pi = (*face)[i++];
1317         if (back_indices[pi]==NULL_VALUE)
1318         {
1319             back_indices[pi] = vertices->size();
1320             vertices->push_back((*orig_vertices)[pi]+backOffset);
1321         }
1322         backFace->push_back(back_indices[pi]);
1323     }
1324 
1325     for(osg::Geometry::PrimitiveSetList::iterator itr = bevelPrimitiveSets.begin();
1326         itr != bevelPrimitiveSets.end();
1327         ++itr)
1328     {
1329         osg::DrawElementsUShort* strip = dynamic_cast<osg::DrawElementsUShort*>(itr->get());
1330         if (!strip) continue;
1331 
1332         osg::CopyOp copyop(osg::CopyOp::DEEP_COPY_ALL);
1333 
1334         osg::DrawElementsUShort* front_strip = new osg::DrawElementsUShort(*strip, copyop);
1335         text_geometry->addPrimitiveSet(front_strip);
1336         for(unsigned int i=0; i<front_strip->size(); ++i)
1337         {
1338             unsigned short& pi  = (*front_strip)[i];
1339             if (front_indices[pi]==NULL_VALUE)
1340             {
1341                 front_indices[pi] = vertices->size();
1342                 vertices->push_back((*orig_vertices)[pi]+frontOffset);
1343             }
1344             pi = front_indices[pi];
1345         }
1346 
1347         for(unsigned int i=0; i<front_strip->size()-1;)
1348         {
1349             unsigned short& p1  = (*front_strip)[i++];
1350             unsigned short& p2  = (*front_strip)[i++];
1351             std::swap(p1,p2);
1352         }
1353 
1354         osg::DrawElementsUShort* back_strip = new osg::DrawElementsUShort(*strip, copyop);
1355         text_geometry->addPrimitiveSet(back_strip);
1356         for(unsigned int i=0; i<back_strip->size(); ++i)
1357         {
1358             unsigned short& pi  = (*back_strip)[i];
1359             if (back_indices[pi]==NULL_VALUE)
1360             {
1361                 back_indices[pi] = vertices->size();
1362                 vertices->push_back((*orig_vertices)[pi]+backOffset);
1363             }
1364             pi = back_indices[pi];
1365         }
1366     }
1367 
1368 
1369     // now build up the shell
1370     for(osg::Geometry::PrimitiveSetList::iterator itr = shellPrimitiveSets.begin();
1371         itr != shellPrimitiveSets.end();
1372         ++itr)
1373     {
1374         osg::DrawElementsUShort* bevel = dynamic_cast<osg::DrawElementsUShort*>(itr->get());
1375         if (!bevel) continue;
1376 
1377         unsigned int no_vertices_on_boundary = bevel->size()/2;
1378 
1379         const osgText::Bevel::Vertices& profileVertices = profile.getVertices();
1380         unsigned int no_vertices_on_bevel = profileVertices.size();
1381 
1382         Indices bevelIndices;
1383         bevelIndices.resize(no_vertices_on_boundary*no_vertices_on_bevel, NULL_VALUE);
1384 
1385         // populate vertices
1386         for(unsigned int i=0; i<no_vertices_on_boundary; ++i)
1387         {
1388             unsigned int topi = (*bevel)[i*2+1];
1389             unsigned int basei = (*bevel)[i*2];
1390 
1391             osg::Vec3 top_vertex = (*orig_vertices)[ topi ] + frontOffset;
1392             osg::Vec3 base_vertex = (*orig_vertices)[ basei ] + frontOffset;
1393             osg::Vec3 up = top_vertex-base_vertex;
1394 
1395             if (front_indices[basei]==NULL_VALUE)
1396             {
1397                 front_indices[basei] = vertices->size();
1398                 vertices->push_back(base_vertex);
1399             }
1400 
1401             bevelIndices[i*no_vertices_on_bevel + 0] = front_indices[basei];
1402 
1403             for(unsigned int j=1; j<no_vertices_on_bevel-1; ++j)
1404             {
1405                 const osg::Vec2& pv = profileVertices[j];
1406                 osg::Vec3 pos( base_vertex + (forward * pv.x()) + (up * pv.y()) );
1407                 bevelIndices[i*no_vertices_on_bevel + j] = vertices->size();
1408                 vertices->push_back(pos);
1409             }
1410 
1411             if (back_indices[basei]==NULL_VALUE)
1412             {
1413                 back_indices[basei] = vertices->size();
1414                 vertices->push_back(base_vertex + forward);
1415             }
1416 
1417             bevelIndices[i*no_vertices_on_bevel + no_vertices_on_bevel-1] = back_indices[basei];
1418         }
1419 
1420         osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(GL_TRIANGLES);
1421         unsigned int base, next;
1422         for(unsigned int i = 0; i< no_vertices_on_boundary-1; ++i)
1423         {
1424             for(unsigned int j=0; j<no_vertices_on_bevel-1; ++j)
1425             {
1426                 base = i*no_vertices_on_bevel + j;
1427                 next = base + no_vertices_on_bevel;
1428 
1429                 elements->push_back(bevelIndices[base]);
1430                 elements->push_back(bevelIndices[base+1]);
1431                 elements->push_back(bevelIndices[next]);
1432 
1433                 elements->push_back(bevelIndices[base+1]);
1434                 elements->push_back(bevelIndices[next+1]);
1435                 elements->push_back(bevelIndices[next]);
1436             }
1437         }
1438 
1439         text_geometry->addPrimitiveSet(elements);
1440     }
1441 
1442 #if 1
1443     osg::Vec4Array* new_colours = new osg::Vec4Array;
1444     new_colours->push_back(osg::Vec4(1.0,1.0,1.0,0.2));
1445     text_geometry->setColorArray(new_colours, osg::Array::BIND_OVERALL);
1446 
1447 
1448     osg::StateSet* stateset = text_geometry->getOrCreateStateSet();
1449     stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
1450     stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
1451     stateset->setAttributeAndModes(new osg::CullFace, osg::StateAttribute::ON);
1452     //stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1453     stateset->setRenderBinDetails(11, "SORT_FRONT_TO_BACK");
1454 #endif
1455     return text_geometry.release();
1456 }
1457 
1458 }
1459