root/OpenSceneGraph/trunk/src/osgPlugins/freetype/FreeTypeFont3D.cpp @ 7696

Revision 7696, 16.0 kB (checked in by robert, 7 years ago)

Added initilizers of variables to FreeTypeFont?3D constructors.

Removed unused FreeTypeFontBase? class

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 "FreeTypeFont3D.h"
15#include "FreeTypeLibrary.h"
16
17
18#include <limits.h>
19#include <fstream>
20
21
22#include <osg/Geometry>
23#include <osg/Notify> 
24#include <osgDB/WriteFile>
25#include <osgUtil/SmoothingVisitor>
26#include <osgUtil/Tessellator>
27
28
29#include <ft2build.h> 
30#include FT_FREETYPE_H
31
32#include <freetype/ftoutln.h>
33#include <freetype/ftbbox.h>
34
35
36
37namespace
38{
39
40struct Char3DInfo
41{
42    Char3DInfo(int numSteps=50):
43        _verts( new osg::Vec3Array ),
44        _geometry( new osg::Geometry ),
45        _idx(0),
46        _numSteps(numSteps),
47        _maxY(-FLT_MAX),
48        _maxX(-FLT_MAX),
49        _minX(FLT_MAX),
50        _minY(FLT_MAX)
51    {
52    }
53    ~Char3DInfo()
54    {
55    }
56
57    osg::Geometry* get()
58    {
59        int len = _verts->size()-_idx;
60        if (len)
61        {
62            _geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POLYGON, _idx, len ) );
63            _idx = _verts->size();
64        }
65
66        _geometry->setVertexArray(_verts.get());
67        return _geometry.get();
68    }
69
70    void moveTo(osg::Vec2 pos)
71    {
72        if (_verts->size())
73        {
74            int len = _verts->size()-_idx;
75            _geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POLYGON, _idx, len ) );
76        }
77        _idx = _verts->size();
78        _verts->push_back( osg::Vec3(pos.x(),pos.y(),0) );
79
80        setMinMax(pos);
81    }
82    void lineTo(osg::Vec2 pos)
83    {
84        _verts->push_back( osg::Vec3(pos.x(),pos.y(),0) );
85        setMinMax(pos);
86    }
87    void conicTo(osg::Vec2 control, osg::Vec2 pos)
88    {
89        osg::Vec3 p0 = _verts->back();
90        osg::Vec3 p1 = osg::Vec3(control.x(),control.y(),0);
91        osg::Vec3 p2 = osg::Vec3(pos.x(),pos.y(),0);
92
93        double dt = 1.0/_numSteps;
94        double u=0;
95        for (int i=0; i<=_numSteps; ++i)
96        {
97            double w = 1;
98            double bs = 1.0/( (1-u)*(1-u)+2*(1-u)*u*w +u*u );
99            osg::Vec3 p = (p0*((1-u)*(1-u)) + p1*(2*(1-u)*u*w) + p2*(u*u))*bs;
100            _verts->push_back( p );
101
102            u += dt;
103        }
104
105        setMinMax(pos);
106    }
107
108    void cubicTo(osg::Vec2 control1, osg::Vec2 control2, osg::Vec2 pos)
109    {
110        osg::Vec3 p0 = _verts->back();
111        osg::Vec3 p1 = osg::Vec3(control1.x(),control1.y(),0);
112        osg::Vec3 p2 = osg::Vec3(control2.x(),control2.y(),0);
113        osg::Vec3 p3 = osg::Vec3(pos.x(),pos.y(),0);
114
115        double cx = 3*(p1.x() - p0.x());
116        double bx = 3*(p2.x() - p1.x()) - cx;
117        double ax = p3.x() - p0.x() - cx - bx;
118        double cy = 3*(p1.y() - p0.y());
119        double by = 3*(p2.y() - p1.y()) - cy;
120        double ay = p3.y() - p0.y() - cy - by;
121
122        double dt = 1.0/_numSteps;
123        double u=0;
124        for (int i=0; i<=_numSteps; ++i)
125        {
126            osg::Vec3 p = osg::Vec3( ax*u*u*u + bx*u*u  + cx*u + p0.x(),ay*u*u*u + by*u*u  + cy*u + p0.y(),0 );
127            _verts->push_back( p );
128
129            u += dt;
130        }
131
132        setMinMax(pos);
133    }
134
135    void setMinMax(osg::Vec2 pos)
136    {
137        _maxY = std::max(_maxY, (double) pos.y());
138        _minY = std::min(_minY, (double) pos.y());
139        _maxX = std::max(_maxX, (double) pos.x());
140        _minX = std::min(_minX, (double) pos.x());
141    }
142
143    osg::ref_ptr<osg::Vec3Array>    _verts;
144    osg::ref_ptr<osg::Geometry>     _geometry;
145    int                             _idx;
146    int                             _numSteps;
147    double                          _maxY;
148    double                          _maxX;
149    double                          _minX;
150    double                          _minY;
151};
152
153
154#define FT_NUM(x) (x/64.0)
155int moveTo( const FT_Vector* to, void* user )
156{
157    Char3DInfo* char3d = (Char3DInfo*)user;
158    char3d->moveTo( osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) );
159    return 0;
160}
161int lineTo( const FT_Vector* to, void* user )
162{
163    Char3DInfo* char3d = (Char3DInfo*)user;
164    char3d->lineTo( osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) );
165    return 0;
166}
167int conicTo( const FT_Vector* control,const FT_Vector* to, void* user )
168{
169    Char3DInfo* char3d = (Char3DInfo*)user;
170    char3d->conicTo( osg::Vec2(FT_NUM(control->x),FT_NUM(control->y)), osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) );
171    return 0;
172}
173int cubicTo( const FT_Vector* control1,const FT_Vector* control2,const FT_Vector* to, void* user )
174{
175    Char3DInfo* char3d = (Char3DInfo*)user;
176    char3d->cubicTo(
177        osg::Vec2(FT_NUM(control1->x),FT_NUM(control1->y)),
178        osg::Vec2(FT_NUM(control2->x),FT_NUM(control2->y)),
179        osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) );
180    return 0;
181}
182#undef FT_NUM
183
184}
185
186
187FreeTypeFont3D::FreeTypeFont3D(const std::string& filename, FT_Face face, unsigned int flags):
188    _filename(filename),
189    _buffer(0),
190    _face(face),
191    _flags(flags),
192    _scale(1.0),
193    _shiftY(0.0),
194    _shiftX(0.0),
195    _charScale(1.0)
196{
197    init();
198}
199
200FreeTypeFont3D::FreeTypeFont3D(FT_Byte* buffer, FT_Face face, unsigned int flags):
201    _filename(""),
202    _buffer(buffer),
203    _face(face),
204    _flags(flags),
205    _scale(1.0),
206    _shiftY(0.0),
207    _shiftX(0.0),
208    _charScale(1.0)
209{
210    init();
211}
212
213void FreeTypeFont3D::init()
214{
215
216    FT_Error _error = FT_Set_Pixel_Sizes(_face, 32, 32);
217    if (_error)
218    {
219        osg::notify(osg::NOTICE) << "FreeTypeFont3D: set pixel sizes failed ..." << std::endl;
220        return;
221    }
222
223    FT_Set_Char_Size( _face, 64*64, 64*64, 600, 600);
224
225    int glyphIndex = FT_Get_Char_Index( _face, 'M' );
226    _error = FT_Load_Glyph( _face, glyphIndex, FT_LOAD_DEFAULT );
227    if (_error)
228    {
229        osg::notify(osg::NOTICE) << "FreeTypeFont3D: initial glyph load failed ..." << std::endl;
230        return;
231    }
232
233    if (_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
234    {
235        osg::notify(osg::NOTICE) << "FreeTypeFont3D: not a vector font" << std::endl;
236        return;
237    }
238
239    {
240        Char3DInfo char3d;
241
242        FT_Outline outline = _face->glyph->outline;
243        FT_Outline_Funcs funcs;
244        funcs.conic_to = (FT_Outline_ConicToFunc)&conicTo;
245        funcs.line_to = (FT_Outline_LineToFunc)&lineTo;
246        funcs.cubic_to = (FT_Outline_CubicToFunc)&cubicTo;
247        funcs.move_to = (FT_Outline_MoveToFunc)&moveTo;
248        funcs.shift = 0;
249        funcs.delta = 0;
250        _error = FT_Outline_Decompose(&outline,&funcs,&char3d);
251        if (_error)
252        {
253            osg::notify(osg::NOTICE) << "FreeTypeFont3D: - outline decompose failed ..." << std::endl;
254            return;
255        }
256
257        FT_BBox bb;
258        FT_Outline_Get_BBox(&outline,&bb);
259
260        long xmin = ft_floor( bb.xMin );
261        long xmax = ft_ceiling( bb.xMax );
262        long ymin = ft_floor( bb.yMin );
263        long ymax = ft_ceiling( bb.yMax );
264
265        double width = (xmax - xmin)/64.0;
266        double height = (ymax - ymin)/64.0;
267
268        _scale = 1.0/height;
269
270        double charHeight = char3d._maxY-char3d._minY;
271        double charWidth = char3d._maxX-char3d._minX;
272
273        double dh = fabs(bb.yMin/64.0)/height;
274        double dw = fabs(bb.xMin/64.0)/width;
275
276        _shiftY = char3d._minY + dh*charHeight;
277        _shiftX = char3d._minX + dw*charWidth;
278
279        _charScale = 1/charHeight;
280    }
281}
282
283FreeTypeFont3D::~FreeTypeFont3D()
284{
285    if(_face)
286    {
287        FreeTypeLibrary* freeTypeLibrary = FreeTypeLibrary::instance();
288        if (freeTypeLibrary)
289        {
290            // remove myself from the local registry to ensure that
291            // not dangling pointers remain
292            freeTypeLibrary->removeFont3DImplmentation(this);
293       
294            // free the freetype font face itself
295            FT_Done_Face(_face);
296            _face = 0;
297
298            // release memory held for FT_Face to work
299            if (_buffer)
300            {
301                delete [] _buffer;
302                _buffer = 0;
303            }
304        }
305    }
306}
307
308
309osgText::Font3D::Glyph3D * FreeTypeFont3D::getGlyph(unsigned int charcode)
310{
311   
312   
313    //
314    // GT: fix for symbol fonts (i.e. the Webdings font) as the wrong character are being 
315    // returned, for symbol fonts in windows (FT_ENCONDING_MS_SYMBOL in freetype) the correct
316    // values are from 0xF000 to 0xF0FF not from 0x000 to 0x00FF (0 to 255) as you would expect. 
317    // Microsoft uses a private field for its symbol fonts
318    //
319    unsigned int charindex = charcode;
320    if (_face->charmap != NULL)
321    {
322        if (_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
323        {
324            charindex |= 0xF000;
325        }
326    }
327
328    FT_Error error = FT_Load_Char( _face, charindex, FT_LOAD_DEFAULT|_flags );
329    if (error)
330    {
331        osg::notify(osg::WARN) << "FT_Load_Char(...) error 0x"<<std::hex<<error<<std::dec<<std::endl;
332        return 0;
333    }
334    if (_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
335    {
336        osg::notify(osg::WARN) << "FreeTypeFont3D::getGlyph : not a vector font" << std::endl;
337        return 0;
338    }
339   
340    // ** init FreeType to describe the glyph
341    Char3DInfo char3d;
342
343    FT_Outline outline = _face->glyph->outline;
344    FT_Outline_Funcs funcs;
345    funcs.conic_to = (FT_Outline_ConicToFunc)&conicTo;
346    funcs.line_to = (FT_Outline_LineToFunc)&lineTo;
347    funcs.cubic_to = (FT_Outline_CubicToFunc)&cubicTo;
348    funcs.move_to = (FT_Outline_MoveToFunc)&moveTo;
349    funcs.shift = 0;
350    funcs.delta = 0;
351   
352    // ** record description
353    FT_Error _error = FT_Outline_Decompose(&outline, &funcs, &char3d);
354    if (_error)
355    {
356        osg::notify(osg::WARN) << "FreeTypeFont3D::getGlyph : - outline decompose failed ..." << std::endl;
357        return 0;
358    }
359   
360    // ** create geometry for each part of the glyph
361    osg::ref_ptr<osg::Geometry> frontGeo(new osg::Geometry);
362    frontGeo->setVertexArray(char3d.get()->getVertexArray());
363    frontGeo->setPrimitiveSetList(char3d.get()->getPrimitiveSetList());
364   
365    osg::ref_ptr<osg::Geometry> wallGeo(new osg::Geometry);
366    wallGeo->setVertexArray(frontGeo->getVertexArray());
367   
368    osg::ref_ptr<osg::Geometry> backGeo(new osg::Geometry);
369    backGeo->setVertexArray(frontGeo->getVertexArray());
370       
371   
372   
373    // ** for conveniance.
374    osg::Vec3Array * vertices = char3d._verts.get();
375   
376   
377   
378    // ** duplicate the vertex for the back face
379    // ** with a depth equal to the font depth
380    std::size_t len = vertices->size();
381    std::size_t dlen = len * 2;
382     
383    vertices->reserve(dlen);
384       
385    osg::Vec3Array::iterator begin = vertices->begin();
386    osg::Vec3Array::iterator it = vertices->begin();
387   
388    for (std::size_t i = 0; i != len; ++i, ++it)
389        vertices->push_back(*it);
390//    std::copy(begin, begin + len, begin + len + 1); TOCHECK
391   
392 
393    // ** and decal new vertices
394    unsigned int depth = _facade->getFontDepth();
395    for (std::size_t i = len; i != dlen; ++i)
396    {
397        (*vertices)[i].z() -= depth;
398    }
399   
400    osg::Vec3Array::iterator end;
401   
402    // ** create wall and back face from the front polygon
403    // **  then accumulate them in the apropriate geometry wallGeo and backGeo
404    for (std::size_t i=0; i < frontGeo->getNumPrimitiveSets(); ++i)
405    {
406        // ** get the front polygon
407        osg::ref_ptr<osg::DrawArrays> daFront(dynamic_cast<osg::DrawArrays*>(frontGeo->getPrimitiveSet(i)));
408        unsigned int idx = daFront->getFirst();
409        unsigned int cnt = daFront->getCount();
410       
411        // ** reverse vertices to draw the front face in the CCW
412        std::reverse(begin + idx, begin + idx + cnt);
413       
414        // ** create the back polygon
415        osg::ref_ptr<osg::DrawArrays> daBack(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, idx + len, cnt));
416        backGeo->addPrimitiveSet(daBack.get());
417       
418       
419        // ** create the wall triangle strip
420        osg::ref_ptr<osg::DrawElementsUInt> deWall(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP));
421        wallGeo->addPrimitiveSet(deWall.get());
422       
423        // **  link triangle strip
424        deWall->push_back(idx + len);
425        for (unsigned int j = 1; j < cnt; ++j)
426        {   
427            deWall->push_back(idx + cnt - j);
428            deWall->push_back(idx + len + j);
429        }
430        deWall->push_back(idx);
431        deWall->push_back(idx + len);
432        deWall->push_back(idx + cnt - 1);
433    }
434
435    // ** tesselate front and back face
436    {
437        osgUtil::Tessellator ts;
438        ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
439        ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
440        ts.retessellatePolygons(*frontGeo);
441    }
442   
443    {
444        osgUtil::Tessellator ts;
445        ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
446        ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
447        ts.retessellatePolygons(*backGeo);
448    }
449
450    // ** generate normal
451    {
452        osgUtil::SmoothingVisitor sm;
453        osg::ref_ptr<osg::Geode> geode(new osg::Geode);
454        geode->addDrawable(wallGeo.get());
455        geode->accept(sm);
456    }
457   
458    // ** save vertices and PrimitiveSetList of each face in the Glyph3D PrimitiveSet face list
459    osgText::Font3D::Glyph3D * glyph3D = new osgText::Font3D::Glyph3D(charcode);
460
461    glyph3D->setVertexArray(dynamic_cast<osg::Vec3Array*>(frontGeo->getVertexArray()));
462   
463    glyph3D->getFrontPrimitiveSetList() = frontGeo->getPrimitiveSetList();
464    glyph3D->getWallPrimitiveSetList() = wallGeo->getPrimitiveSetList();
465    glyph3D->getBackPrimitiveSetList() = backGeo->getPrimitiveSetList();
466
467   
468    FT_Glyph_Metrics* metrics = &(_face->glyph->metrics);
469
470    glyph3D->setHorizontalBearing(osg::Vec2((float)metrics->horiBearingX/64.0f,(float)(metrics->horiBearingY-metrics->height)/64.0f)); // bottom left.
471    glyph3D->setHorizontalAdvance((float)metrics->horiAdvance/64.0f);
472    glyph3D->setVerticalBearing(osg::Vec2((float)metrics->vertBearingX/64.0f,(float)(metrics->vertBearingY-metrics->height)/64.0f)); // top middle.
473    glyph3D->setVerticalAdvance((float)metrics->vertAdvance/64.0f);
474
475    glyph3D->setWidth((float)metrics->width / 64.0f);
476    glyph3D->setHeight((float)metrics->height / 64.0f);
477
478   
479    FT_BBox ftbb;
480    FT_Outline_Get_BBox(&outline, &ftbb);
481
482    long xmin = ft_floor( ftbb.xMin );
483    long xmax = ft_ceiling( ftbb.xMax );
484    long ymin = ft_floor( ftbb.yMin );
485    long ymax = ft_ceiling( ftbb.yMax );
486       
487    osg::BoundingBox bb(xmin / 64.0f, ymin / 64.0f, 0.0f, xmax / 64.0f, ymax / 64.0f, 0.0f);
488   
489    glyph3D->setBoundingBox(bb);
490   
491    return glyph3D;
492}
493
494osg::Vec2 FreeTypeFont3D::getKerning(unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType kerningType)
495{
496    if (!FT_HAS_KERNING(_face) || (kerningType == osgText::KERNING_NONE)) return osg::Vec2(0.0f,0.0f);
497
498    FT_Kerning_Mode mode = (kerningType==osgText::KERNING_DEFAULT) ? ft_kerning_default : ft_kerning_unfitted;
499
500    // convert character code to glyph index
501    FT_UInt left = FT_Get_Char_Index( _face, leftcharcode );
502    FT_UInt right = FT_Get_Char_Index( _face, rightcharcode );
503   
504    // get the kerning distances.   
505    FT_Vector  kerning;
506
507    FT_Error error = FT_Get_Kerning( _face,                     // handle to face object
508                                     left,                      // left glyph index
509                                     right,                     // right glyph index
510                                     mode,                      // kerning mode
511                                     &kerning );                // target vector
512
513    if (error)
514    {
515        osg::notify(osg::WARN) << "FT_Get_Kerning(...) returned error code " <<std::hex<<error<<std::dec<< std::endl;
516        return osg::Vec2(0.0f,0.0f);
517    }
518
519    return osg::Vec2((float)kerning.x/64.0f,(float)kerning.y/64.0f);
520}
521
522bool FreeTypeFont3D::hasVertical() const
523{
524    return FT_HAS_VERTICAL(_face)!=0;
525}
526
527float FreeTypeFont3D::getScale() const 
528{
529    return _scale;
530}
Note: See TracBrowser for help on using the browser.