Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

OSGTextFT2Backend.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038 
00039 #ifdef _MSC_VER
00040 # pragma warning (disable: 4786)
00041 #endif
00042 
00043 #include "OSGTextFT2Backend.h"
00044 #include <OSGBaseTypes.h>
00045 
00046 
00047 #ifdef FT2_LIB
00048 
00049 
00050 #include "OSGTextPixmapFace.h"
00051 #include "OSGTextPixmapGlyph.h"
00052 #include "OSGTextVectorFace.h"
00053 #include "OSGTextVectorGlyph.h"
00054 #include "OSGTextTXFFace.h"
00055 #include "OSGTextTXFGlyph.h"
00056 #include "OSGTextLayoutParam.h"
00057 #include "OSGTextLayoutResult.h"
00058 
00059 #include <iostream>
00060 #include <algorithm>
00061 #include <set>
00062 #ifdef FONTCONFIG_LIB
00063 # include <fontconfig/fontconfig.h>
00064 #else
00065 # ifdef _WIN32
00066 #  include <windows.h>
00067 # else
00068 #  include <dirent.h>
00069 # endif
00070 #endif
00071 
00072 // ?????
00073 #ifdef _MSC_VER
00074 # include <freetype/ftoutln.h>
00075 #else
00076 # include FT_OUTLINE_H
00077 #endif
00078 
00079 
00080 using namespace std;
00081 
00082 
00083 OSG_BEGIN_NAMESPACE
00084 
00085 
00086 //----------------------------------------------------------------------
00087 // Freetype2 specific implementation of the TextVectorFace class
00088 // Author: pdaehne
00089 //----------------------------------------------------------------------
00090 class TextFT2VectorFace: public TextVectorFace
00091 {
00092 public:
00093 
00094     // Constructor
00095     TextFT2VectorFace(FT_Face face);
00096 
00097     // Destructor
00098     virtual ~TextFT2VectorFace();
00099 
00100     // Lays out one line of text
00101     virtual void layout(const wstring &text, const TextLayoutParam &param,
00102                         TextLayoutResult &layoutResult);
00103 
00104 protected:
00105 
00106     // Creates a new Glyph object
00107     virtual auto_ptr<TextVectorGlyph> createGlyph(TextGlyph::Index glyphIndex);
00108 
00109 private:
00110 
00111     // Freetype face object
00112     FT_Face _face;
00113 };
00114 
00115 
00116 //----------------------------------------------------------------------
00117 // Freetype2 specific implementation of the TextVectorGlyph class
00118 // Author: pdaehne
00119 //----------------------------------------------------------------------
00120 class TextFT2VectorGlyph: public TextVectorGlyph
00121 {
00122 public:
00123 
00124     // Constructor
00125     TextFT2VectorGlyph(Index glyphIndex, Real32 scale, FT_GlyphSlot glyphSlot);
00126 
00127     // Destructor
00128     virtual ~TextFT2VectorGlyph();
00129 };
00130 
00131 
00132 //----------------------------------------------------------------------
00133 // Freetype2 specific implementation of the TextPixmapFace class
00134 // Author: pdaehne
00135 //----------------------------------------------------------------------
00136 class TextFT2PixmapFace: public TextPixmapFace
00137 {
00138 public:
00139 
00140     // Constructor
00141     TextFT2PixmapFace(FT_Face face, UInt32 size);
00142 
00143     // Destructor
00144     virtual ~TextFT2PixmapFace();
00145 
00146     // Lays out one line of text
00147     virtual void layout(const wstring &text, const TextLayoutParam &param,
00148                         TextLayoutResult &layoutResult);
00149 
00150 protected:
00151 
00152     // Creates a new Glyph object
00153     virtual auto_ptr<TextPixmapGlyph> createGlyph(TextGlyph::Index glyphIndex);
00154 
00155 private:
00156 
00157     // Freetype face object
00158     FT_Face _face;
00159 };
00160 
00161 
00162 //----------------------------------------------------------------------
00163 // Freetype2 specific implementation of the TextPixmapGlyph class
00164 // Author: pdaehne
00165 //----------------------------------------------------------------------
00166 class TextFT2PixmapGlyph: public TextPixmapGlyph
00167 {
00168 public:
00169 
00170     // Constructor
00171     TextFT2PixmapGlyph(Index glyphIndex, TextFT2PixmapFace *face, FT_GlyphSlot glyphSlot);
00172 
00173     // Destructor
00174     virtual ~TextFT2PixmapGlyph();
00175 };
00176 
00177 
00178 //----------------------------------------------------------------------
00179 // Freetype2 specific implementation of the TextTXFFace class
00180 // Author: pdaehne
00181 //----------------------------------------------------------------------
00182 class TextFT2TXFFace: public TextTXFFace
00183 {
00184 public:
00185 
00186     // Constructor
00187     TextFT2TXFFace(FT_Face face, const TextTXFParam &param);
00188 
00189     // Destructor
00190     virtual ~TextFT2TXFFace();
00191 };
00192 
00193 
00194 //----------------------------------------------------------------------
00195 // Freetype2 specific implementation of the TextTXFGlyph class
00196 // Author: pdaehne
00197 //----------------------------------------------------------------------
00198 class TextFT2TXFGlyph: public TextTXFGlyph
00199 {
00200 public:
00201 
00202     // Constructor
00203     TextFT2TXFGlyph(Index glyphIndex, TextFT2TXFFace *face,
00204                     Real32 scale, FT_GlyphSlot glyphSlot);
00205 
00206     // Destructor
00207     virtual ~TextFT2TXFGlyph();
00208 };
00209 
00210 
00211 //----------------------------------------------------------------------
00212 // Constructor
00213 // Author: pdaehne
00214 //----------------------------------------------------------------------
00215 TextFT2Backend::TextFT2Backend()
00216 : TextBackend(), _library(0)
00217 #ifndef FONTCONFIG_LIB
00218   ,
00219 # ifdef FONT_SEARCHPATH
00220  _pathList(FONT_SEARCHPATH),
00221 #else
00222 _pathList(),
00223 #endif
00224  _scanForFonts(true), _fontMap()
00225 #endif
00226 {
00227     // Initialize Freetype library
00228     FT_Error error = FT_Init_FreeType(&_library);
00229     if (error)
00230         // There is not much we can do here when we cannot initialize
00231         // the library - we simply will not be able to create any font
00232         _library = 0;
00233 
00234 #ifdef FONTCONFIG_LIB
00235 
00236     // Initialize FontConfig library
00237     FcInit();
00238     // Again, we do not check for errors - see comment above
00239 
00240 #endif // FONTCONFIG_LIB
00241 
00242 }
00243 
00244 
00245 //----------------------------------------------------------------------
00246 // Destructor
00247 // Author: pdaehne
00248 //----------------------------------------------------------------------
00249 TextFT2Backend::~TextFT2Backend()
00250 {
00251     // Deinitialize Freetype library
00252     if (_library != 0)
00253         FT_Done_FreeType(_library);
00254 
00255 #ifdef FONTCONFIG_LIB
00256 
00257     // Deinitialize FontConfig library
00258     // Hmmm, this is mentioned in the documentation, but nowhere
00259     // defined in the header files (at least for my version of the
00260     // library)
00261     //FcFini();
00262 
00263 #endif // FONTCONFIG_LIB
00264 }
00265 
00266 
00267 //----------------------------------------------------------------------
00268 // Tries to find the path and the index of a font
00269 // Author: pdaehne
00270 //----------------------------------------------------------------------
00271 bool TextFT2Backend::findPath(const string &family, TextFace::Style style,
00272                               string &path, int &index)
00273 {
00274     // Initialize result values
00275     path.erase();
00276     index = -1;
00277 
00278 #ifdef FONTCONFIG_LIB
00279 
00280     // Handle generic family names
00281     string f;
00282     if (family == "SERIF")
00283         f = "serif";
00284     else if (family == "SANS")
00285         f = "sans-serif";
00286     else if (family == "TYPEWRITER")
00287         f = "monospace";
00288     else
00289         f = family;
00290 
00291     // Create FontConfig search pattern
00292     FcPattern *pattern = FcPatternCreate();
00293     if (pattern == 0)
00294         return false;
00295 
00296     // We are only interested in outline fonts
00297     if (FcPatternAddBool(pattern, FC_OUTLINE, FcTrue) == FcFalse)
00298     {
00299         FcPatternDestroy(pattern);
00300         return false;
00301     }
00302 
00303     // Set font family
00304     if (FcPatternAddString(pattern, FC_FAMILY, (const FcChar8*)f.c_str()) == FcFalse)
00305     {
00306         FcPatternDestroy(pattern);
00307         return false;
00308     }
00309 
00310     // Set style
00311     int slant;
00312     int weight;
00313     switch (style)
00314     {
00315     default:
00316     case TextFace::STYLE_PLAIN:
00317         slant = FC_SLANT_ROMAN;
00318         weight = FC_WEIGHT_MEDIUM;
00319         break;
00320     case TextFace::STYLE_BOLD:
00321         slant = FC_SLANT_ROMAN;
00322         weight = FC_WEIGHT_BOLD;
00323         break;
00324     case TextFace::STYLE_ITALIC:
00325         slant = FC_SLANT_ITALIC;
00326         weight = FC_WEIGHT_MEDIUM;
00327         break;
00328     case TextFace::STYLE_BOLDITALIC:
00329         slant = FC_SLANT_ITALIC;
00330         weight = FC_WEIGHT_BOLD;
00331         break;
00332     }
00333     if (FcPatternAddInteger(pattern, FC_SLANT, slant) == FcFalse)
00334     {
00335         FcPatternDestroy(pattern);
00336         return false;
00337     }
00338     if (FcPatternAddInteger(pattern, FC_WEIGHT, weight) == FcFalse)
00339     {
00340         FcPatternDestroy(pattern);
00341         return false;
00342     }
00343 
00344     // Do some magic stuff... Taken from FontConfig example programs
00345     if (FcConfigSubstitute(0, pattern, FcMatchPattern) == FcFalse)
00346     {
00347         FcPatternDestroy(pattern);
00348         return false;
00349     }
00350     FcDefaultSubstitute(pattern);
00351 
00352     // Search for a matching font
00353     FcResult result;
00354     FcPattern *match = FcFontMatch(0, pattern, &result);
00355     // We do not need the search pattern any more
00356     FcPatternDestroy(pattern);
00357     if (match == 0)
00358         return false;
00359 
00360     // Get path to font file
00361     FcChar8 *pathPtr;
00362     if (FcPatternGetString(match, FC_FILE, 0, &pathPtr) != FcResultMatch)
00363     {
00364         FcPatternDestroy(match);
00365         return false;
00366     }
00367     path = (const char *)pathPtr;
00368 
00369     // Get index of face in the font file
00370     if (FcPatternGetInteger(match, FC_INDEX, 0, &index) != FcResultMatch)
00371     {
00372         FcPatternDestroy(match);
00373         return false;
00374     }
00375 
00376     // Destroy the match pattern
00377     FcPatternDestroy(match);
00378 
00379 #else // !FONTCONFIG_LIB
00380 
00381     // Scan the font search path for fonts
00382     scanForFonts();
00383 
00384     // Try to find a matching font
00385     FontMap::const_iterator it, bestMatchIt = _fontMap.end();
00386     pair<FontMap::const_iterator, FontMap::const_iterator> range;
00387     //string f = family;
00388     //transform(f.begin(), f.end(), f.begin(), ::tolower);
00389     range = _fontMap.equal_range(/*f*/family);
00390     for (it = range.first; it != range.second; ++it)
00391     {
00392         if (it->second.style == style)
00393         {
00394             bestMatchIt = it;
00395             break;
00396         }
00397     }
00398     if (bestMatchIt == _fontMap.end())
00399         return false;
00400     path = bestMatchIt->second.path;
00401     index = bestMatchIt->second.index;
00402 
00403 #endif // !FONTCONFIG_LIB
00404 
00405     return true;
00406 }
00407 
00408 
00409 //----------------------------------------------------------------------
00410 // Tries to create a freetype2 face
00411 // Author: pdaehne
00412 //----------------------------------------------------------------------
00413 FT_Face TextFT2Backend::createFace(const string &family, TextFace::Style style, FT_UInt size)
00414 {
00415     // Check if we have a valid freetype2 library handle
00416     if (_library == 0)
00417         return 0;
00418 
00419     // Try to find the path and the index of a font
00420     string path;
00421     int index;
00422     if (findPath(family, style, path, index) == false)
00423         return 0;
00424 
00425     // Try to open the font file
00426     FT_Face face;
00427     FT_Error error = FT_New_Face(_library, path.c_str(), index, &face);
00428     if (error)
00429         return 0;
00430 
00431     // Does this Face have a family name?
00432     // If not, just use the family name used to find it.
00433     if(face->family_name == NULL)
00434         face->family_name = strdup(family.c_str());
00435         
00436     // Select unicode character map
00437     // Freetype should do this automatically, but in fact it
00438     // does not do it for Type1 fonts -pdaehne
00439     error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
00440     // Don't care if this went wrong, maybe we still get correct results
00441 
00442     // Set the size
00443     if (size > 0)
00444         error = FT_Set_Pixel_Sizes(face, 0, size);
00445         // Again, we deliberately do not care for errors
00446 
00447     // For Type1 fonts, attach metric file
00448     string::size_type pos = path.rfind('.');
00449     if (pos != string::npos)
00450     {
00451         string suffix = path.substr(pos + 1);
00452         transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower);
00453         if ((suffix == "pfb") || (suffix == "pfa"))
00454         {
00455             string addPath = path.substr(0, pos + 1);
00456             addPath.append("afm");
00457             error = FT_Attach_File(face, addPath.c_str());
00458             // Don't care if this went wrong, the face will still work
00459         }
00460     }
00461 
00462     return face;
00463 }
00464 
00465 
00466 //----------------------------------------------------------------------
00467 // Creates a new vector face
00468 // Author: pdaehne
00469 //----------------------------------------------------------------------
00470 TextVectorFace*
00471 TextFT2Backend::createVectorFace(const string &family, TextFace::Style style)
00472 {
00473     // Try to create the freetype2 face
00474     FT_Face face = createFace(family, style, 0);
00475     if (face == 0)
00476         return 0;
00477 
00478     // Create and return the new face object
00479     return new TextFT2VectorFace(face);
00480 }
00481 
00482 
00483 //----------------------------------------------------------------------
00484 // Creates a new pixmap face
00485 // Author: pdaehne
00486 //----------------------------------------------------------------------
00487 TextPixmapFace*
00488 TextFT2Backend::createPixmapFace(const string &family, TextFace::Style style, UInt32 size)
00489 {
00490     // Try to create the freetype2 face
00491     FT_Face face = createFace(family, style, size);
00492     if (face == 0)
00493         return 0;
00494 
00495     // Create and return the new face object
00496     return new TextFT2PixmapFace(face, size);
00497 }
00498 
00499 
00500 //----------------------------------------------------------------------
00501 // Creates a new TXF face
00502 // Author: pdaehne
00503 //----------------------------------------------------------------------
00504 TextTXFFace*
00505 TextFT2Backend::createTXFFace(const string &family, TextFace::Style style, const TextTXFParam &param)
00506 {
00507     // Try to create the freetype2 face
00508     FT_Face face = createFace(family, style, param.size);
00509     if (face == 0)
00510         return 0;
00511 
00512     // Create and return the new face object
00513     return new TextFT2TXFFace(face, param);
00514 }
00515 
00516 
00517 //----------------------------------------------------------------------
00518 // Returns the names of all font families available
00519 // Author: pdaehne
00520 //----------------------------------------------------------------------
00521 void TextFT2Backend::getFontFamilies(vector<string> &families)
00522 {
00523     // Initialize the result vector
00524     families.clear();
00525 
00526 #ifdef FONTCONFIG_LIB
00527 
00528     // Create a pattern that matches all fonts
00529     FcPattern *pattern = FcPatternCreate();
00530     if (pattern == 0)
00531         return;
00532 
00533     // We are only interested in the names of the font families
00534     FcObjectSet *objectSet = FcObjectSetBuild(FC_FAMILY, 0);
00535     if (objectSet == 0)
00536     {
00537         FcPatternDestroy(pattern);
00538         return;
00539     }
00540 
00541     // Get all available fonts and put their names into the vector
00542     FcFontSet *fontSet = FcFontList(0, pattern, objectSet);
00543     if (fontSet != 0)
00544     {
00545         int    i;
00546         set<string> familySet;
00547         for (i = 0; i < fontSet->nfont; ++i)
00548         {
00549             FcChar8 *family;
00550             if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch)
00551                 familySet.insert(reinterpret_cast<char*>(family));
00552         }
00553         // GRRRR, this does not work on WIN32...
00554         //families.assign(familySet.begin(), familySet.end());
00555         families.resize(familySet.size());
00556         copy(familySet.begin(), familySet.end(), families.begin());
00557         FcFontSetDestroy(fontSet);
00558     }
00559 
00560     // Cleanup
00561     FcObjectSetDestroy(objectSet);
00562     FcPatternDestroy(pattern);
00563 
00564 #else // !FONTCONFIG_LIB
00565 
00566     // Scan the font search path for fonts
00567     scanForFonts();
00568 
00569     // Put the available fonts into the vector
00570     families.reserve(_fontMap.size());
00571     FontMap::const_iterator it;
00572     for (it = _fontMap.begin(); it != _fontMap.end(); ++it)
00573         families.push_back(it->first);
00574     unique(families.begin(), families.end());
00575 
00576 #endif // !FONTCONFIG_LIB
00577 }
00578 
00579 
00580 //----------------------------------------------------------------------
00581 // Scans the font search path for fonts
00582 // Author: pdaehne
00583 //----------------------------------------------------------------------
00584 #ifndef FONTCONFIG_LIB
00585 void TextFT2Backend::scanForFonts()
00586 {
00587     // We scan the font directory only once
00588     if (_scanForFonts == true)
00589     {
00590         _scanForFonts = false;
00591 
00592         // Split the path list into its components
00593         string::size_type start = 0;
00594         while (true)
00595         {
00596 #ifdef _WIN32
00597             string::size_type end = _pathList.find(';', start);
00598 #else
00599             string::size_type end = _pathList.find(':', start);
00600 #endif
00601             string path = end == string::npos ? _pathList.substr(start) : _pathList.substr(start, end - start);
00602 
00603             // Remove whitespace
00604             string::size_type wsPos = path.find_first_not_of(" \t\r\n");
00605             if (wsPos != string::npos)
00606             {
00607                 path.erase(0, wsPos);
00608                 wsPos = path.find_last_not_of(" \t\r\n");
00609                 path.erase(wsPos + 1);
00610 
00611                 // Scan the directory for fonts
00612                 scanDir(path);
00613             }
00614 
00615             if (end == string::npos)
00616                 break;
00617             start = end + 1;
00618         }
00619     }
00620 }
00621 #endif // !FONTCONFIG_LIB
00622 
00623 
00624 //----------------------------------------------------------------------
00625 // Scans a directory and its subdirectories for fonts
00626 // Author: pdaehne
00627 //----------------------------------------------------------------------
00628 #ifndef FONTCONFIG_LIB
00629 void TextFT2Backend::scanDir(const string &path)
00630 {
00631 #ifdef _WIN32
00632 
00633     // Append a slash to the end of the path if necessary
00634     string p = path;
00635     if ((p.length() < 1) || ((p[p.length() - 1] != '/') && (p[p.length() - 1] != '\\')))
00636         p.append(1, '\\');
00637 
00638     // Try to find the first directory entry
00639     string pattern = p;
00640     pattern.append(1, '*');
00641     WIN32_FIND_DATA findFileData;
00642     HANDLE hFind = FindFirstFile(pattern.c_str(), &findFileData);
00643     if (hFind == INVALID_HANDLE_VALUE)
00644         return;
00645 
00646     while (true)
00647     {
00648         // Create the full path of the directory entry
00649         string name = findFileData.cFileName;
00650         string fullname = p;
00651         fullname.append(name);
00652 
00653         if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
00654         {
00655             // Recursively scan subdirectories
00656             if ((name != ".") && (name != ".."))
00657                 scanDir(fullname);
00658         }
00659         else
00660             // Try to open the file as a font
00661             checkFile(fullname);
00662 
00663         // Try to find the next directory entry
00664         if (FindNextFile(hFind, &findFileData) == FALSE)
00665             break;
00666     }
00667 
00668     // Finished
00669     FindClose(hFind);
00670 
00671 #else // !_WIN32
00672 
00673     // Open the directory
00674     DIR *dir = opendir(path.c_str());
00675     if (dir == 0)
00676         return;
00677 
00678     // Append a slash to the end of the path if necessary
00679     string p = path;
00680     if ((p.length() < 1) || (p[p.length() - 1] != '/'))
00681         p.append(1, '/');
00682 
00683     struct dirent entry, *result;
00684     while (true)
00685     {
00686         // Try to get the next directory entry
00687         if (readdir_r(dir, &entry, &result) != 0)
00688             return;
00689         if (result == 0)
00690             break;
00691 
00692         // Create the full path of the directory entry
00693         string name = entry.d_name;
00694         string fullname = p;
00695         fullname.append(name);
00696         switch (entry.d_type)
00697         {
00698             case DT_DIR:
00699                 // Recursively scan subdirectories
00700                 if ((name != ".") && (name != ".."))
00701                     scanDir(fullname);
00702                 break;
00703             case DT_REG:
00704                 // Try to open the file as a font
00705                 checkFile(fullname);
00706                 break;
00707             default:
00708                 break;
00709         }
00710     }
00711 
00712     // Finished
00713     closedir(dir);
00714 
00715 #endif // !_WIN32
00716 
00717 }
00718 #endif // !FONTCONFIG_LIB
00719 
00720 
00721 //----------------------------------------------------------------------
00722 // Checks if a file is a font file
00723 // Author: pdaehne
00724 //----------------------------------------------------------------------
00725 #ifndef FONTCONFIG_LIB
00726 void TextFT2Backend::checkFile(const string &fullname)
00727 {
00728     // Try to open the file as a font
00729     FT_Long index = 0;
00730     FT_Long numFaces = 1;
00731     while (index < numFaces)
00732     {
00733         FT_Face face;
00734         FT_Error error = FT_New_Face(_library, fullname.c_str(), index, &face);
00735         if (error)
00736             break;
00737 
00738         // We got a font - put it into the map of fonts
00739         numFaces = face->num_faces;
00740         FontInfo fontInfo;
00741         fontInfo.path = fullname;
00742         fontInfo.index = index;
00743         if (face->style_flags & FT_STYLE_FLAG_BOLD)
00744             fontInfo.style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_BOLDITALIC : TextFace::STYLE_BOLD;
00745         else
00746             fontInfo.style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_ITALIC : TextFace::STYLE_PLAIN;
00747         string family = face->family_name;
00748         //transform(family.begin(), family.end(), family.begin(), ::tolower);
00749         _fontMap.insert(FontMap::value_type(family, fontInfo));
00750         FT_Done_Face(face);
00751 
00752         ++index;
00753     }
00754 }
00755 #endif // !FONTCONFIG_LIB
00756 
00757 
00758 //----------------------------------------------------------------------
00759 // Returns information about a face
00760 // Author: pdaehne
00761 //----------------------------------------------------------------------
00762 static void getFaceInfo(FT_Face face, string &family, TextFace::Style &style)
00763 {
00764     // Determine the family name
00765     family = face->family_name;
00766 
00767     // Determine the style
00768     if (face->style_flags & FT_STYLE_FLAG_BOLD)
00769         style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_BOLDITALIC : TextFace::STYLE_BOLD;
00770     else
00771         style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_ITALIC : TextFace::STYLE_PLAIN;
00772 }
00773 
00774 
00775 //----------------------------------------------------------------------
00776 // Constructor
00777 // Author: pdaehne
00778 //----------------------------------------------------------------------
00779 TextFT2VectorFace::TextFT2VectorFace(FT_Face face)
00780 : TextVectorFace(), _face(face)
00781 {
00782     // Get information about the face
00783     getFaceInfo(_face, _family, _style);
00784 
00785     // Determine the scale factor
00786     _scale = 1.f / static_cast<Real32>(_face->ascender - _face->descender);
00787 
00788     // Determine ascent
00789     _horiAscent = static_cast<Real32>(_face->ascender) * _scale;
00790     _vertAscent = -0.5f;
00791 
00792     // Determine descent
00793     _horiDescent = static_cast<Real32>(_face->descender) * _scale;
00794     _vertDescent = 0.5f;
00795 }
00796 
00797 
00798 //----------------------------------------------------------------------
00799 // Destructor
00800 // Author: pdaehne
00801 //----------------------------------------------------------------------
00802 TextFT2VectorFace::~TextFT2VectorFace()
00803 {
00804     // Close the font file
00805     FT_Done_Face(_face);
00806 }
00807 
00808 
00809 //----------------------------------------------------------------------
00810 // Lays out one line of text
00811 // Author: pdaehne
00812 //----------------------------------------------------------------------
00813 void TextFT2VectorFace::layout(const wstring &text, const TextLayoutParam &param,
00814                                TextLayoutResult &layoutResult)
00815 {
00816     // Initialize return values
00817     layoutResult.clear();
00818 
00819     // Do the layout depending on the direction
00820     FT_UInt previousGlyphIndex = 0;
00821     Vec2f currPos;
00822     size_t i, len = text.length();
00823     layoutResult.indices.reserve(len);
00824     layoutResult.positions.reserve(len);
00825     vector<UInt32> spaceIndices;
00826     bool justify = param.getLength(0) > 0.f;
00827     for (i = 0; i < len; ++i)
00828     {
00829         // Get glyph
00830         FT_UInt glyphIndex = FT_Get_Char_Index(_face, text[i]);
00831         const TextGlyph &glyph = getGlyph(glyphIndex);
00832         if ((justify == true) && (text[i] == ' '))
00833             spaceIndices.push_back(layoutResult.indices.size());
00834 
00835         // Calculate position
00836         Vec2f pos;
00837         if (param.horizontal == true)
00838         {
00839             if (param.leftToRight == true)
00840             {
00841                 FT_Vector kerning;
00842                 FT_Get_Kerning(_face, previousGlyphIndex, glyphIndex, ft_kerning_unscaled/*FT_KERNING_UNSCALED*/, &kerning);
00843                 currPos[0] += static_cast<float>(kerning.x) * _scale;
00844                 pos = currPos;
00845                 pos[0] += glyph.getHoriBearingX();
00846                 pos[1] += glyph.getHoriBearingY();
00847                 currPos[0] += glyph.getHoriAdvance();
00848             }
00849             else // leftToRight == false
00850             {
00851                 FT_Vector kerning;
00852                 FT_Get_Kerning(_face, glyphIndex, previousGlyphIndex, ft_kerning_unscaled/*FT_KERNING_UNSCALED*/, &kerning);
00853                 currPos[0] -= static_cast<float>(kerning.x) * _scale + glyph.getHoriAdvance();
00854                 pos = currPos;
00855                 pos[0] += glyph.getHoriBearingX();
00856                 pos[1] += glyph.getHoriBearingY();
00857             }
00858             previousGlyphIndex = glyphIndex;
00859         }
00860         else // horizontal == false
00861         {
00862             if (param.topToBottom == true)
00863             {
00864                 pos = currPos;
00865                 pos[0] += glyph.getVertBearingX();
00866                 pos[1] += glyph.getVertBearingY();
00867                 currPos[1] += glyph.getVertAdvance();
00868             }
00869             else // topToBottom == false
00870             {
00871                 currPos[1] -= glyph.getVertAdvance();
00872                 pos = currPos;
00873                 pos[0] += glyph.getVertBearingX();
00874                 pos[1] += glyph.getVertBearingY();
00875             }
00876         }
00877 
00878         layoutResult.indices.push_back(glyphIndex);
00879         layoutResult.positions.push_back(pos);
00880     }
00881 
00882     // Justify the line
00883     if (justify == true)
00884         justifyLine(param, spaceIndices, currPos, layoutResult);
00885 
00886     // Adjust the origin depending on the major and the minor alignment
00887     adjustLineOrigin(param, currPos, layoutResult);
00888 
00889     // Determine text bounds / line bounds
00890     if (param.horizontal == true)
00891         layoutResult.textBounds.setValues(osgabs(currPos.x()), _horiAscent - _horiDescent);
00892     else
00893         layoutResult.textBounds.setValues(_vertDescent - _vertAscent, osgabs(currPos.y()));
00894     layoutResult.lineBounds.push_back(layoutResult.textBounds);
00895 }
00896 
00897 
00898 //----------------------------------------------------------------------
00899 // Helper object used by the decompose callback functions
00900 // Author: pdaehne
00901 //----------------------------------------------------------------------
00902 typedef struct UserData
00903 {
00904     Real32 scale;
00905     Vec2f offset;
00906     TextVectorGlyph::Outline &outline;
00907     inline UserData(Real32 s, const Vec2f &off, TextVectorGlyph::Outline &o)
00908     : scale(s), offset(off), outline(o)
00909     {}
00910 }
00911 UserData;
00912 
00913 
00914 //----------------------------------------------------------------------
00915 // callback function that starts a new contour
00916 // Author: pdaehne
00917 //----------------------------------------------------------------------
00918 static int moveToFunc(FT_Vector *to, void *user)
00919 {
00920     UserData *userData = reinterpret_cast<UserData*>(user);
00921 
00922     // Check if the previous contour is valid, i.e. if it has more than two points.
00923     // When not, we simply delete the contour.
00924     if (userData->outline.empty() == false)
00925         if (userData->outline.back().size() < 3)
00926             userData->outline.erase(userData->outline.end() - 1);
00927 
00928     // We start a new contour
00929     userData->outline.push_back(TextVectorGlyph::Contour());
00930 
00931     // We have a point on the line
00932     Vec2f p(to->x, to->y);
00933     p *= userData->scale;
00934     p -= userData->offset;
00935     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00936 
00937     // Continue
00938     return 0;
00939 }
00940 
00941 
00942 //----------------------------------------------------------------------
00943 // callback function that adds a line to the contour
00944 // Author: pdaehne
00945 //----------------------------------------------------------------------
00946 static int lineToFunc(FT_Vector *to, void *user)
00947 {
00948     UserData *userData = reinterpret_cast<UserData*>(user);
00949 
00950     // We have a point on the line
00951     Vec2f p(to->x, to->y);
00952     p *= userData->scale;
00953     p -= userData->offset;
00954     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00955 
00956     // Continue
00957     return 0;
00958 }
00959 
00960 
00961 //----------------------------------------------------------------------
00962 // callback function that adds a quadratic Bezier spline to the contour
00963 // Author: pdaehne
00964 //----------------------------------------------------------------------
00965 static int conicToFunc(FT_Vector *control, FT_Vector *to, void *user)
00966 {
00967     UserData *userData = reinterpret_cast<UserData*>(user);
00968 
00969     // We have a control point and a point on the line
00970     Vec2f p(control->x, control->y);
00971     p *= userData->scale;
00972     p -= userData->offset;
00973     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_QUAD));
00974     p.setValues(to->x, to->y);
00975     p *= userData->scale;
00976     p -= userData->offset;
00977     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00978 
00979     // Continue
00980     return 0;
00981 }
00982 
00983 
00984 //----------------------------------------------------------------------
00985 // callback function that adds a cubic Bezier spline to the contour
00986 // Author: pdaehne
00987 //----------------------------------------------------------------------
00988 static int cubicToFunc(FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *user)
00989 {
00990     UserData *userData = reinterpret_cast<UserData*>(user);
00991 
00992     // We have two control points and a point on the line
00993     Vec2f p(control1->x, control1->y);
00994     p *= userData->scale;
00995     p -= userData->offset;
00996     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
00997     p.setValues(control2->x, control2->y);
00998     p *= userData->scale;
00999     p -= userData->offset;
01000     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
01001     p.setValues(to->x, to->y);
01002     p *= userData->scale;
01003     p -= userData->offset;
01004     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
01005 
01006     // Continue
01007     return 0;
01008 }
01009 
01010 
01011 //----------------------------------------------------------------------
01012 // Creates a new Glyph object
01013 // Author: pdaehne
01014 //----------------------------------------------------------------------
01015 auto_ptr<TextVectorGlyph> TextFT2VectorFace::createGlyph(TextGlyph::Index glyphIndex)
01016 {
01017     // We cannot create glyphs for invalid glyph indices
01018     if (glyphIndex == TextGlyph::INVALID_INDEX)
01019         return auto_ptr<TextVectorGlyph>();
01020 
01021     // Try to get the glyph
01022     FT_Error error = FT_Load_Glyph(_face, glyphIndex, FT_LOAD_NO_SCALE);
01023     if (error)
01024         return auto_ptr<TextVectorGlyph>();
01025 
01026     // We are only interested in outlines
01027     FT_GlyphSlot glyphSlot = _face->glyph;
01028     if (glyphSlot->format != ft_glyph_format_outline/*FT_GLYPH_FORMAT_OUTLINE*/)
01029         return auto_ptr<TextVectorGlyph>();
01030 
01031     // Create and return the new glyph object
01032     return auto_ptr<TextVectorGlyph>(new TextFT2VectorGlyph(glyphIndex, _scale, glyphSlot));
01033 }
01034 
01035 
01036 //----------------------------------------------------------------------
01037 // Constructor
01038 // Author: pdaehne
01039 //----------------------------------------------------------------------
01040 TextFT2VectorGlyph::TextFT2VectorGlyph(Index glyphIndex, float scale, FT_GlyphSlot glyphSlot)
01041 : TextVectorGlyph()
01042 {
01043     _glyphIndex = glyphIndex;
01044     _width = static_cast<Real32>(glyphSlot->metrics.width) * scale;
01045     _height = static_cast<Real32>(glyphSlot->metrics.height) * scale;
01046 
01047     // Determine horizontal glyph metrics
01048     _horiAdvance = static_cast<Real32>(glyphSlot->metrics.horiAdvance) * scale;
01049     _horiBearingX = static_cast<Real32>(glyphSlot->metrics.horiBearingX) * scale;
01050     _horiBearingY = static_cast<Real32>(glyphSlot->metrics.horiBearingY) * scale;
01051 
01052     // Determine vertical glyph metrics
01053     // Hmmm, there is no useful information here for vertical layout.
01054     // So we have to guess resonable values -pdaehne
01055     //_vertAdvance = -static_cast<Real32>(glyphSlot->metrics.vertAdvance) * scale;
01056     //_vertBearingX = static_cast<Real32>(glyphSlot->metrics.vertBearingX) * scale;
01057     //_vertBearingY = -static_cast<Real32>(glyphSlot->metrics.vertBearingY) * scale;
01058     _vertAdvance = -_height - 1.f / 10.f;
01059     _vertBearingX = -_width / 2.f;
01060     _vertBearingY = -1.f / 20.f;
01061 
01062     // Add the outlines to the glyph object
01063     FT_Outline_Funcs func_interface =
01064     {
01065         moveToFunc,
01066         lineToFunc,
01067         conicToFunc,
01068         cubicToFunc,
01069         0,
01070         0
01071     };
01072     UserData userData(scale, Vec2f(_horiBearingX, _horiBearingY), _outline);
01073     FT_Outline_Decompose(&(glyphSlot->outline), &func_interface, &userData);
01074 
01075     // Check if the last contour is valid, i.e. if it has more than two points.
01076     // When not, we simply delete the contour.
01077     if (_outline.empty() == false)
01078         if (_outline.back().size() < 3)
01079             _outline.erase(_outline.end() - 1);
01080 }
01081 
01082 
01083 //----------------------------------------------------------------------
01084 // Destructor
01085 // Author: pdaehne
01086 //----------------------------------------------------------------------
01087 TextFT2VectorGlyph::~TextFT2VectorGlyph() {}
01088 
01089 
01090 //----------------------------------------------------------------------
01091 // Constructor
01092 // Author: pdaehne
01093 //----------------------------------------------------------------------
01094 TextFT2PixmapFace::TextFT2PixmapFace(FT_Face face, UInt32 size)
01095 : TextPixmapFace(), _face(face)
01096 {
01097     // Get information about the face
01098     getFaceInfo(_face, _family, _style);
01099 
01100     // Set the size
01101     _size = size;
01102 
01103     // Determine ascent
01104     _horiAscent = static_cast<Real32>(_face->size->metrics.ascender) / 64.f;
01105     _vertAscent = -static_cast<Real32>(_size) / 2.f;
01106 
01107     // Determine descent
01108     _horiDescent = static_cast<Real32>(_face->size->metrics.descender) / 64.f;
01109     _vertDescent = static_cast<Real32>(_size) / 2.f;
01110 }
01111 
01112 
01113 //----------------------------------------------------------------------
01114 // Destructor
01115 // Author: pdaehne
01116 //----------------------------------------------------------------------
01117 TextFT2PixmapFace::~TextFT2PixmapFace()
01118 {
01119     // Close the font file
01120     FT_Done_Face(_face);
01121 }
01122 
01123 
01124 //----------------------------------------------------------------------
01125 // Lays out one line of text
01126 // Author: pdaehne
01127 //----------------------------------------------------------------------
01128 void TextFT2PixmapFace::layout(const wstring &text, const TextLayoutParam &param,
01129                                TextLayoutResult &layoutResult)
01130 {
01131     // Initialize return values
01132     layoutResult.clear();
01133 
01134     // Do the layout depending on the direction
01135     FT_UInt previousGlyphIndex = 0;
01136     Vec2f currPos;
01137     size_t i, len = text.length();
01138     layoutResult.indices.reserve(len);
01139     layoutResult.positions.reserve(len);
01140     vector<UInt32> spaceIndices;
01141     bool justify = param.getLength(0) > 0.f;
01142     for (i = 0; i < len; ++i)
01143     {
01144         // Get glyph
01145         FT_UInt glyphIndex = FT_Get_Char_Index(_face, text[i]);
01146         const TextGlyph &glyph = getGlyph(glyphIndex);
01147         if ((justify == true) && (text[i] == ' '))
01148             spaceIndices.push_back(layoutResult.indices.size());
01149 
01150         // Calculate position
01151         Vec2f pos;
01152         if (param.horizontal == true)
01153         {
01154             if (param.leftToRight == true)
01155             {
01156                 FT_Vector kerning;
01157                 FT_Get_Kerning(_face, previousGlyphIndex, glyphIndex, ft_kerning_default/*FT_KERNING_DEFAULT*/, &kerning);
01158                 currPos[0] += static_cast<float>(kerning.x) / 64.f;
01159                 pos[0] = currPos.x() + glyph.getHoriBearingX();
01160                 pos[1] = currPos.y() + glyph.getHoriBearingY();
01161                 currPos[0] += glyph.getHoriAdvance();
01162             }
01163             else // leftToRight == false
01164             {
01165                 FT_Vector kerning;
01166                 FT_Get_Kerning(_face, glyphIndex, previousGlyphIndex, ft_kerning_default/*FT_KERNING_DEFAULT*/, &kerning);
01167                 currPos[0] -= static_cast<float>(kerning.x) / 64.f + glyph.getHoriAdvance();
01168                 pos[0] = currPos[0] + glyph.getHoriBearingX();
01169                 pos[1] = currPos[1] + glyph.getHoriBearingY();
01170             }
01171             previousGlyphIndex = glyphIndex;
01172         }
01173         else // horizontal == false
01174         {
01175             if (param.topToBottom == true)
01176             {
01177                 pos[0] = currPos.x() + glyph.getVertBearingX();
01178                 pos[1] = currPos.y() + glyph.getVertBearingY();
01179                 currPos[1] += glyph.getVertAdvance();
01180             }
01181             else // topToBottom == false
01182             {
01183                 currPos[1] -= glyph.getVertAdvance();
01184                 pos[0] = currPos.x() + glyph.getVertBearingX();
01185                 pos[1] = currPos.y() + glyph.getVertBearingY();
01186             }
01187         }
01188 
01189         layoutResult.indices.push_back(glyphIndex);
01190         layoutResult.positions.push_back(pos);
01191     }
01192 
01193     // Justify the line
01194     if (justify == true)
01195         justifyLine(param, spaceIndices, currPos, layoutResult);
01196 
01197     // Adjust the origin depending on the major and the minor alignment
01198     adjustLineOrigin(param, currPos, layoutResult);
01199 
01200     // Determine text bounds / line bounds
01201     if (param.horizontal == true)
01202         layoutResult.textBounds.setValues(osgabs(currPos.x()), _horiAscent - _horiDescent);
01203     else
01204         layoutResult.textBounds.setValues(_vertDescent - _vertAscent, osgabs(currPos.y()));
01205     layoutResult.lineBounds.push_back(layoutResult.textBounds);
01206 }
01207 
01208 
01209 //----------------------------------------------------------------------
01210 // Creates a new Glyph object
01211 // Author: pdaehne
01212 //----------------------------------------------------------------------
01213 auto_ptr<TextPixmapGlyph> TextFT2PixmapFace::createGlyph(TextGlyph::Index glyphIndex)
01214 {
01215     // We cannot create glyphs for invalid glyph indices
01216     if (glyphIndex == TextGlyph::INVALID_INDEX)
01217         return auto_ptr<TextPixmapGlyph>();
01218 
01219     // Try to get the glyph
01220     FT_Error error = FT_Load_Glyph(_face, glyphIndex, FT_LOAD_DEFAULT);
01221     if (error)
01222         return auto_ptr<TextPixmapGlyph>();
01223 
01224     // We are only interested in outlines
01225     FT_GlyphSlot glyphSlot = _face->glyph;
01226     if (glyphSlot->format != ft_glyph_format_bitmap/*FT_GLYPH_FORMAT_BITMAP*/)
01227     {
01228         error = FT_Render_Glyph(glyphSlot, ft_render_mode_normal/*FT_RENDER_MODE_NORMAL*/);
01229         if (error)
01230             return auto_ptr<TextPixmapGlyph>();
01231     }
01232 
01233     // Create and return the new glyph object
01234     return auto_ptr<TextPixmapGlyph>(new TextFT2PixmapGlyph(glyphIndex, this, glyphSlot));
01235 }
01236 
01237 
01238 //----------------------------------------------------------------------
01239 // Constructor
01240 // Author: pdaehne
01241 //----------------------------------------------------------------------
01242 TextFT2PixmapGlyph::TextFT2PixmapGlyph(Index glyphIndex, TextFT2PixmapFace *face, FT_GlyphSlot glyphSlot)
01243 : TextPixmapGlyph()
01244 {
01245     _glyphIndex = glyphIndex;
01246     _width = glyphSlot->bitmap.width;
01247     _pitch = glyphSlot->bitmap.pitch;
01248     _height = glyphSlot->bitmap.rows;
01249 
01250     // Determine horizontal glyph metrics
01251     _horiAdvance = static_cast<Real32>(glyphSlot->metrics.horiAdvance) / 64.f;
01252     _horiBearingX = glyphSlot->bitmap_left;
01253     _horiBearingY = glyphSlot->bitmap_top;
01254 
01255     // Determine vertical glyph metrics
01256     // Hmmm, there is no useful information here for vertical layout.
01257     // So we have to guess resonable values -pdaehne
01258     //_vertAdvance = -static_cast<Real32>(glyphSlot->metrics.vertAdvance) / 64.f;
01259     //_vertBearingX = static_cast<int>(static_cast<float>(glyphSlot->metrics.vertBearingX) / 64.f);
01260     //_vertBearingY = static_cast<int>(-static_cast<float>(glyphSlot->metrics.vertBearingY) / 64.f);
01261     _vertBearingX = -static_cast<Int32>(_width >> 1);
01262     _vertBearingY = static_cast<Int32>(-(face->getHoriAscent() - face->getHoriDescent()) / 20.f);
01263     if (_vertBearingY > -1)
01264         _vertBearingY = -1;
01265     Int32 vertAdvanceOffset = _vertBearingY << 1;
01266     _vertAdvance = -static_cast<Int32>(_height) + vertAdvanceOffset;
01267 
01268     unsigned int size = glyphSlot->bitmap.pitch * glyphSlot->bitmap.rows;
01269     if ((size == 0) || (glyphSlot->bitmap.buffer == 0))
01270         _pixmap = 0;
01271     else
01272     {
01273         _pixmap = new unsigned char[size];
01274         memcpy(_pixmap, glyphSlot->bitmap.buffer, size);
01275         flipPixmap();
01276     }
01277 }
01278 
01279 
01280 //----------------------------------------------------------------------
01281 // Destructor
01282 // Author: pdaehne
01283 //----------------------------------------------------------------------
01284 TextFT2PixmapGlyph::~TextFT2PixmapGlyph() {}
01285 
01286 
01287 //----------------------------------------------------------------------
01288 // Constructor
01289 // Author: pdaehne
01290 //----------------------------------------------------------------------
01291 TextFT2TXFFace::TextFT2TXFFace(FT_Face face, const TextTXFParam &param)
01292 {
01293     // Get information about the face
01294     getFaceInfo(face, _family, _style);
01295 
01296     // Set the size
01297     _param = param;
01298 
01299     // Determine ascent
01300     _horiAscent = static_cast<Real32>(face->size->metrics.ascender) / 64.f;
01301     _vertAscent = -0.5f;
01302 
01303     // Determine descent
01304     _horiDescent = static_cast<Real32>(face->size->metrics.descender) / 64.f;
01305     _vertDescent = 0.5f;
01306 
01307     // Determine the scale factor & adjust ascent and descent
01308     _scale = 1.f / (_horiAscent - _horiDescent);
01309     _horiAscent *= _scale;
01310     _horiDescent *= _scale;
01311 
01312     // Create all glyphs
01313     wstring::const_iterator it;
01314     for (it = param.getCharacters().begin(); it != param.getCharacters().end(); ++it)
01315     {
01316         FT_UInt glyphIndex = FT_Get_Char_Index(face, *it);
01317         if (glyphIndex == 0)
01318             continue;
01319         FT_Error error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT);
01320         if (error)
01321             continue;
01322         FT_GlyphSlot glyphSlot = face->glyph;
01323         if (glyphSlot->format != ft_glyph_format_bitmap/*FT_GLYPH_FORMAT_BITMAP*/)
01324         {
01325             error = FT_Render_Glyph(glyphSlot, ft_render_mode_normal/*FT_RENDER_MODE_NORMAL*/);
01326             if (error)
01327                 continue;
01328         }
01329         _glyphMap.insert(GlyphMap::value_type(*it, new TextFT2TXFGlyph(*it, this, _scale, face->glyph)));
01330     }
01331 
01332     // Calculate the positions of the glyphs on the texture
01333     prepareTexture(param);
01334     assert(_texture != NullFC);
01335     assert(_texture->getSize() == static_cast<UInt32>(_texture->getWidth() * _texture->getHeight()));
01336 
01337     // Create the texture
01338     beginEditCP(_texture);
01339     for (it = param.getCharacters().begin(); it != param.getCharacters().end(); ++it)
01340     {
01341         GlyphMap::iterator gIt = _glyphMap.find(*it);
01342         if (gIt == _glyphMap.end())
01343             continue;
01344         assert(gIt->second != 0);
01345         TextTXFGlyph *glyph = gIt->second;
01346         FT_UInt glyphIndex = FT_Get_Char_Index(face, *it);
01347         if (glyphIndex == 0)
01348             continue;
01349         FT_Error error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT);
01350         if (error)
01351             continue;
01352         FT_GlyphSlot glyphSlot = face->glyph;
01353         if (glyphSlot->format != ft_glyph_format_bitmap/*FT_GLYPH_FORMAT_BITMAP*/)
01354         {
01355             error = FT_Render_Glyph(glyphSlot, ft_render_mode_normal/*FT_RENDER_MODE_NORMAL*/);
01356             if (error)
01357                 continue;
01358         }
01359         unsigned char *src = glyphSlot->bitmap.buffer;
01360         if (src == 0)
01361             continue;
01362         int bpl = glyphSlot->bitmap.pitch;
01363         src += bpl * (glyph->getPixmapHeight() - 1);
01364         unsigned char *src2;
01365         UInt8 *dst = _texture->getData() + glyph->getX() + glyph->getY() * _texture->getWidth();
01366         UInt32 dstPitch = _texture->getWidth() - glyph->getPixmapWidth();
01367         UInt32 x, y;
01368         for (y = 0; y < glyph->getPixmapHeight(); ++y)
01369         {
01370             src2 = src;
01371             for (x = 0; x < glyph->getPixmapWidth(); ++x)
01372                 *dst++ = *src2++;
01373             src -= bpl;
01374             dst += dstPitch;
01375         }
01376     }
01377     beginEditCP(_texture);
01378 
01379     // Close the font file
01380     FT_Done_Face(face);
01381 }
01382 
01383 
01384 //----------------------------------------------------------------------
01385 // Destructor
01386 // Author: pdaehne
01387 //----------------------------------------------------------------------
01388 TextFT2TXFFace::~TextFT2TXFFace() {}
01389 
01390 
01391 //----------------------------------------------------------------------
01392 // Constructor
01393 // Author: pdaehne
01394 //----------------------------------------------------------------------
01395 TextFT2TXFGlyph::TextFT2TXFGlyph(Index glyphIndex, TextFT2TXFFace *face,
01396                                  Real32 scale, FT_GlyphSlot glyphSlot)
01397 : TextTXFGlyph()
01398 {
01399     _glyphIndex = glyphIndex;
01400     _scale = scale;
01401     _width = glyphSlot->bitmap.width;
01402     _height = glyphSlot->bitmap.rows;
01403 
01404     // Determine horizontal glyph metrics
01405     _horiAdvance = static_cast<Real32>(glyphSlot->metrics.horiAdvance) / 64.f * _scale;
01406     _horiBearingX = glyphSlot->bitmap_left;
01407     _horiBearingY = glyphSlot->bitmap_top;
01408 
01409     // Determine vertical glyph metrics
01410     // Hmmm, there is no useful information here for vertical layout.
01411     // So we have to guess resonable values -pdaehne
01412     //_vertAdvance = -static_cast<Real32>(glyphSlot->metrics.vertAdvance) / 64.f * _scale;
01413     //_vertBearingX = static_cast<int>(static_cast<float>(glyphSlot->metrics.vertBearingX) / 64.f);
01414     //_vertBearingY = static_cast<int>(-static_cast<float>(glyphSlot->metrics.vertBearingY) / 64.f);
01415     _vertBearingX = -static_cast<Int32>(_width >> 1);
01416     if (glyphIndex == 32)
01417     {
01418         _vertBearingY = -_horiBearingX;
01419         _vertAdvance = -_horiAdvance;
01420     }
01421     else
01422     {
01423         _vertBearingY = static_cast<Int32>(-(face->getHoriAscent() - face->getHoriDescent()) / _scale / 20.f);
01424         if (_vertBearingY > -1)
01425             _vertBearingY = -1;
01426         Real32 vertAdvanceOffset = static_cast<Real32>(_vertBearingY) * 2.f * _scale;
01427         _vertAdvance = -static_cast<Real32>(_height) * _scale + vertAdvanceOffset;
01428     }
01429 }
01430 
01431 
01432 //----------------------------------------------------------------------
01433 // Destructor
01434 // Author: pdaehne
01435 //----------------------------------------------------------------------
01436 TextFT2TXFGlyph::~TextFT2TXFGlyph() {}
01437 
01438 
01439 OSG_END_NAMESPACE
01440 
01441 
01442 #endif // FT2_LIB
01443 
01444 
01445 /*------------------------------------------------------------------------*/
01446 /*                              cvs id's                                  */
01447 
01448 #ifdef OSG_SGI_CC
01449 #pragma set woff 1174
01450 #endif
01451 
01452 #ifdef OSG_LINUX_ICC
01453 #pragma warning( disable : 177 )
01454 #endif
01455 
01456 namespace
01457 {
01458     static OSG::Char8 cvsid_cpp[] = "@(#)$Id: OSGTextFT2Backend.cpp,v 1.3 2005/06/29 21:10:43 dirk Exp $";
01459     static OSG::Char8 cvsid_hpp[] = OSGTEXTFT2BACKEND_HEADER_CVSID;
01460     static OSG::Char8 cvsid_inl[] = OSGTEXTFT2BACKEND_INLINE_CVSID;
01461 }
01462 
01463 #ifdef __sgi
01464 #pragma reset woff 1174
01465 #endif

Generated on Thu Aug 25 04:11:18 2005 for OpenSG by  doxygen 1.4.3