PageRenderTime 65ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/System/Text/OSGTextFT2Backend.cpp

https://github.com/danguilliams/OpenSGDevMaster_Toolbox
C++ | 1475 lines | 876 code | 232 blank | 367 comment | 203 complexity | 29f777134af21b050ec9bde2f5324f7f MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause
  1. /*---------------------------------------------------------------------------*\
  2. * OpenSG *
  3. * *
  4. * *
  5. * Copyright (C) 2000-2002 by the OpenSG Forum *
  6. * *
  7. * www.opensg.org *
  8. * *
  9. * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
  10. * *
  11. \*---------------------------------------------------------------------------*/
  12. /*---------------------------------------------------------------------------*\
  13. * License *
  14. * *
  15. * This library is free software; you can redistribute it and/or modify it *
  16. * under the terms of the GNU Library General Public License as published *
  17. * by the Free Software Foundation, version 2. *
  18. * *
  19. * This library is distributed in the hope that it will be useful, but *
  20. * WITHOUT ANY WARRANTY; without even the implied warranty of *
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
  22. * Library General Public License for more details. *
  23. * *
  24. * You should have received a copy of the GNU Library General Public *
  25. * License along with this library; if not, write to the Free Software *
  26. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
  27. * *
  28. \*---------------------------------------------------------------------------*/
  29. /*---------------------------------------------------------------------------*\
  30. * Changes *
  31. * *
  32. * *
  33. * *
  34. * *
  35. * *
  36. * *
  37. \*---------------------------------------------------------------------------*/
  38. #ifdef _MSC_VER
  39. # pragma warning (disable: 4786)
  40. #endif
  41. #include "OSGTextFT2Backend.h"
  42. #include "OSGBaseTypes.h"
  43. #ifdef OSG_WITH_FT2
  44. #include "OSGTextPixmapFace.h"
  45. #include "OSGTextPixmapGlyph.h"
  46. #include "OSGTextVectorFace.h"
  47. #include "OSGTextVectorGlyph.h"
  48. #include "OSGTextTXFFace.h"
  49. #include "OSGTextTXFGlyph.h"
  50. #include "OSGTextLayoutParam.h"
  51. #include "OSGTextLayoutResult.h"
  52. #include <iostream>
  53. #include <algorithm>
  54. #include <set>
  55. #ifdef OSG_WITH_FONTCONFIG
  56. # include <fontconfig/fontconfig.h>
  57. #else
  58. # ifdef _WIN32
  59. # include <windows.h>
  60. # else
  61. # include <dirent.h>
  62. # endif
  63. #endif
  64. // ?????
  65. #ifdef _MSC_VER
  66. # include <freetype/ftoutln.h>
  67. #else
  68. # include FT_OUTLINE_H
  69. #endif
  70. using namespace std;
  71. OSG_BEGIN_NAMESPACE
  72. //----------------------------------------------------------------------
  73. // Freetype2 specific implementation of the TextVectorFace class
  74. // Author: pdaehne
  75. //----------------------------------------------------------------------
  76. class TextFT2VectorFace: public TextVectorFace
  77. {
  78. public:
  79. // Constructor
  80. TextFT2VectorFace(FT_Face face);
  81. // Destructor
  82. virtual ~TextFT2VectorFace();
  83. // Lays out one line of text
  84. virtual void layout(const wstring &text, const TextLayoutParam &param,
  85. TextLayoutResult &layoutResult);
  86. protected:
  87. // Creates a new Glyph object
  88. virtual auto_ptr<TextVectorGlyph> createGlyph(TextGlyph::Index glyphIndex);
  89. private:
  90. // Freetype face object
  91. FT_Face _face;
  92. };
  93. //----------------------------------------------------------------------
  94. // Freetype2 specific implementation of the TextVectorGlyph class
  95. // Author: pdaehne
  96. //----------------------------------------------------------------------
  97. class TextFT2VectorGlyph: public TextVectorGlyph
  98. {
  99. public:
  100. // Constructor
  101. TextFT2VectorGlyph(Index glyphIndex, Real32 scale, FT_GlyphSlot glyphSlot);
  102. // Destructor
  103. virtual ~TextFT2VectorGlyph();
  104. };
  105. //----------------------------------------------------------------------
  106. // Freetype2 specific implementation of the TextPixmapFace class
  107. // Author: pdaehne
  108. //----------------------------------------------------------------------
  109. class TextFT2PixmapFace: public TextPixmapFace
  110. {
  111. public:
  112. // Constructor
  113. TextFT2PixmapFace(FT_Face face, UInt32 size);
  114. // Destructor
  115. virtual ~TextFT2PixmapFace();
  116. // Lays out one line of text
  117. virtual void layout(const wstring &text, const TextLayoutParam &param,
  118. TextLayoutResult &layoutResult);
  119. protected:
  120. // Creates a new Glyph object
  121. virtual auto_ptr<TextPixmapGlyph> createGlyph(TextGlyph::Index glyphIndex);
  122. private:
  123. // Freetype face object
  124. FT_Face _face;
  125. };
  126. //----------------------------------------------------------------------
  127. // Freetype2 specific implementation of the TextPixmapGlyph class
  128. // Author: pdaehne
  129. //----------------------------------------------------------------------
  130. class TextFT2PixmapGlyph: public TextPixmapGlyph
  131. {
  132. public:
  133. // Constructor
  134. TextFT2PixmapGlyph(Index glyphIndex, TextFT2PixmapFace *face, FT_GlyphSlot glyphSlot);
  135. // Destructor
  136. virtual ~TextFT2PixmapGlyph();
  137. };
  138. //----------------------------------------------------------------------
  139. // Freetype2 specific implementation of the TextTXFFace class
  140. // Author: pdaehne
  141. //----------------------------------------------------------------------
  142. class TextFT2TXFFace: public TextTXFFace
  143. {
  144. public:
  145. // Constructor
  146. TextFT2TXFFace(FT_Face face, const TextTXFParam &param);
  147. // Destructor
  148. virtual ~TextFT2TXFFace();
  149. };
  150. //----------------------------------------------------------------------
  151. // Freetype2 specific implementation of the TextTXFGlyph class
  152. // Author: pdaehne
  153. //----------------------------------------------------------------------
  154. class TextFT2TXFGlyph: public TextTXFGlyph
  155. {
  156. public:
  157. // Constructor
  158. TextFT2TXFGlyph(Index glyphIndex, TextFT2TXFFace *face,
  159. Real32 scale, FT_GlyphSlot glyphSlot);
  160. // Destructor
  161. virtual ~TextFT2TXFGlyph();
  162. };
  163. //----------------------------------------------------------------------
  164. // Constructor
  165. // Author: pdaehne
  166. //----------------------------------------------------------------------
  167. TextFT2Backend::TextFT2Backend()
  168. : TextBackend(),
  169. _library (0)
  170. #ifndef OSG_WITH_FONTCONFIG
  171. ,
  172. # ifdef FONT_SEARCHPATH
  173. _pathList(FONT_SEARCHPATH),
  174. #else
  175. _pathList(),
  176. #endif
  177. _scanForFonts(true),
  178. _fontMap()
  179. #endif
  180. {
  181. // Initialize Freetype library
  182. FT_Error error = FT_Init_FreeType(&_library);
  183. if (error)
  184. // There is not much we can do here when we cannot initialize
  185. // the library - we simply will not be able to create any font
  186. _library = 0;
  187. #ifdef OSG_WITH_FONTCONFIG
  188. // Initialize FontConfig library
  189. FcInit();
  190. // Again, we do not check for errors - see comment above
  191. #endif // OSG_WITH_FONTCONFIG
  192. }
  193. //----------------------------------------------------------------------
  194. // Destructor
  195. // Author: pdaehne
  196. //----------------------------------------------------------------------
  197. TextFT2Backend::~TextFT2Backend()
  198. {
  199. // Deinitialize Freetype library
  200. if (_library != 0)
  201. FT_Done_FreeType(_library);
  202. #ifdef OSG_WITH_FONTCONFIG
  203. // Deinitialize FontConfig library
  204. // Hmmm, this is mentioned in the documentation, but nowhere
  205. // defined in the header files (at least for my version of the
  206. // library)
  207. //FcFini();
  208. #endif // OSG_WITH_FONTCONFIG
  209. }
  210. //----------------------------------------------------------------------
  211. // Tries to find the path and the index of a font
  212. // Author: pdaehne
  213. //----------------------------------------------------------------------
  214. bool TextFT2Backend::findPath(const string &family, TextFace::Style style,
  215. string &path, int &index)
  216. {
  217. // Initialize result values
  218. path.erase();
  219. index = -1;
  220. #ifdef OSG_WITH_FONTCONFIG
  221. // Handle generic family names
  222. string f;
  223. if (family == "SERIF")
  224. f = "serif";
  225. else if (family == "SANS")
  226. f = "sans-serif";
  227. else if (family == "TYPEWRITER")
  228. f = "monospace";
  229. else
  230. f = family;
  231. // Create FontConfig search pattern
  232. FcPattern *pattern = FcPatternCreate();
  233. if (pattern == 0)
  234. return false;
  235. // We are only interested in outline fonts
  236. if (FcPatternAddBool(pattern, FC_OUTLINE, FcTrue) == FcFalse)
  237. {
  238. FcPatternDestroy(pattern);
  239. return false;
  240. }
  241. // Set font family
  242. if (FcPatternAddString(pattern,
  243. FC_FAMILY,
  244. reinterpret_cast<
  245. const FcChar8*>(f.c_str())) == FcFalse)
  246. {
  247. FcPatternDestroy(pattern);
  248. return false;
  249. }
  250. // Set style
  251. int slant;
  252. int weight;
  253. switch (style)
  254. {
  255. default:
  256. FWARNING(("Invalid font style parameter.\n"));
  257. // intentionally fall through
  258. case TextFace::STYLE_PLAIN:
  259. slant = FC_SLANT_ROMAN;
  260. weight = FC_WEIGHT_MEDIUM;
  261. break;
  262. case TextFace::STYLE_BOLD:
  263. slant = FC_SLANT_ROMAN;
  264. weight = FC_WEIGHT_BOLD;
  265. break;
  266. case TextFace::STYLE_ITALIC:
  267. slant = FC_SLANT_ITALIC;
  268. weight = FC_WEIGHT_MEDIUM;
  269. break;
  270. case TextFace::STYLE_BOLDITALIC:
  271. slant = FC_SLANT_ITALIC;
  272. weight = FC_WEIGHT_BOLD;
  273. break;
  274. }
  275. if (FcPatternAddInteger(pattern, FC_SLANT, slant) == FcFalse)
  276. {
  277. FcPatternDestroy(pattern);
  278. return false;
  279. }
  280. if (FcPatternAddInteger(pattern, FC_WEIGHT, weight) == FcFalse)
  281. {
  282. FcPatternDestroy(pattern);
  283. return false;
  284. }
  285. // Do some magic stuff... Taken from FontConfig example programs
  286. if (FcConfigSubstitute(0, pattern, FcMatchPattern) == FcFalse)
  287. {
  288. FcPatternDestroy(pattern);
  289. return false;
  290. }
  291. FcDefaultSubstitute(pattern);
  292. // Search for a matching font
  293. FcResult result;
  294. FcPattern *match = FcFontMatch(0, pattern, &result);
  295. // We do not need the search pattern any more
  296. FcPatternDestroy(pattern);
  297. if (match == 0)
  298. return false;
  299. // Get path to font file
  300. FcChar8 *pathPtr;
  301. if (FcPatternGetString(match, FC_FILE, 0, &pathPtr) != FcResultMatch)
  302. {
  303. FcPatternDestroy(match);
  304. return false;
  305. }
  306. path = reinterpret_cast<const char *>(pathPtr);
  307. // Get index of face in the font file
  308. if (FcPatternGetInteger(match, FC_INDEX, 0, &index) != FcResultMatch)
  309. {
  310. FcPatternDestroy(match);
  311. return false;
  312. }
  313. // Destroy the match pattern
  314. FcPatternDestroy(match);
  315. #else // !OSG_WITH_FONTCONFIG
  316. // Scan the font search path for fonts
  317. scanForFonts();
  318. // Try to find a matching font
  319. FontMap::const_iterator it, bestMatchIt = _fontMap.end();
  320. pair<FontMap::const_iterator, FontMap::const_iterator> range;
  321. //string f = family;
  322. //transform(f.begin(), f.end(), f.begin(), ::tolower);
  323. range = _fontMap.equal_range(/*f*/family);
  324. for (it = range.first; it != range.second; ++it)
  325. {
  326. if (it->second.style == style)
  327. {
  328. bestMatchIt = it;
  329. break;
  330. }
  331. }
  332. if (bestMatchIt == _fontMap.end())
  333. return false;
  334. path = bestMatchIt->second.path;
  335. index = bestMatchIt->second.index;
  336. #endif // !OSG_WITH_FONTCONFIG
  337. return true;
  338. }
  339. //----------------------------------------------------------------------
  340. // Tries to create a freetype2 face
  341. // Author: pdaehne
  342. //----------------------------------------------------------------------
  343. FT_Face TextFT2Backend::createFace(const string &family, TextFace::Style style, FT_UInt size)
  344. {
  345. // Check if we have a valid freetype2 library handle
  346. if (_library == 0)
  347. return 0;
  348. // Try to find the path and the index of a font
  349. string path;
  350. int index;
  351. if (findPath(family, style, path, index) == false)
  352. return 0;
  353. // Try to open the font file
  354. FT_Face face;
  355. FT_Error error = FT_New_Face(_library, path.c_str(), index, &face);
  356. if (error)
  357. return 0;
  358. // Does this Face have a family name?
  359. // If not, just use the family name used to find it.
  360. if(face->family_name == NULL)
  361. face->family_name = strdup(family.c_str());
  362. // Select unicode character map
  363. // Freetype should do this automatically, but in fact it
  364. // does not do it for Type1 fonts -pdaehne
  365. error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
  366. // Don't care if this went wrong, maybe we still get correct results
  367. // Set the size
  368. if (size > 0)
  369. error = FT_Set_Pixel_Sizes(face, 0, size);
  370. // Again, we deliberately do not care for errors
  371. // For Type1 fonts, attach metric file
  372. string::size_type pos = path.rfind('.');
  373. if (pos != string::npos)
  374. {
  375. string suffix = path.substr(pos + 1);
  376. transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower);
  377. if ((suffix == "pfb") || (suffix == "pfa"))
  378. {
  379. string addPath = path.substr(0, pos + 1);
  380. addPath.append("afm");
  381. error = FT_Attach_File(face, addPath.c_str());
  382. // Don't care if this went wrong, the face will still work
  383. }
  384. }
  385. return face;
  386. }
  387. //----------------------------------------------------------------------
  388. // Creates a new vector face
  389. // Author: pdaehne
  390. //----------------------------------------------------------------------
  391. TextVectorFaceTransitPtr
  392. TextFT2Backend::createVectorFace(const string &family, TextFace::Style style)
  393. {
  394. TextVectorFaceTransitPtr retVal;
  395. // Try to create the freetype2 face
  396. FT_Face face = createFace(family, style, 0);
  397. if(face != 0)
  398. {
  399. // Create the new face object
  400. retVal = new TextFT2VectorFace(face);
  401. }
  402. return retVal;
  403. }
  404. //----------------------------------------------------------------------
  405. // Creates a new pixmap face
  406. // Author: pdaehne
  407. //----------------------------------------------------------------------
  408. TextPixmapFaceTransitPtr
  409. TextFT2Backend::createPixmapFace(const string &family, TextFace::Style style, UInt32 size)
  410. {
  411. TextPixmapFaceTransitPtr retVal;
  412. // Try to create the freetype2 face
  413. FT_Face face = createFace(family, style, size);
  414. if (face != 0)
  415. {
  416. // Create the new face object
  417. retVal = new TextFT2PixmapFace(face, size);
  418. }
  419. return retVal;
  420. }
  421. //----------------------------------------------------------------------
  422. // Creates a new TXF face
  423. // Author: pdaehne
  424. //----------------------------------------------------------------------
  425. TextTXFFaceTransitPtr
  426. TextFT2Backend::createTXFFace(const string &family, TextFace::Style style, const TextTXFParam &param)
  427. {
  428. TextTXFFaceTransitPtr retVal;
  429. // Try to create the freetype2 face
  430. FT_Face face = createFace(family, style, param.size);
  431. if (face != 0)
  432. {
  433. // Create and return the new face object
  434. retVal = new TextFT2TXFFace(face, param);
  435. }
  436. return retVal;
  437. }
  438. //----------------------------------------------------------------------
  439. // Returns the names of all font families available
  440. // Author: pdaehne
  441. //----------------------------------------------------------------------
  442. void TextFT2Backend::getFontFamilies(vector<string> &families)
  443. {
  444. // Initialize the result vector
  445. families.clear();
  446. #ifdef OSG_WITH_FONTCONFIG
  447. // Create a pattern that matches all fonts
  448. FcPattern *pattern = FcPatternCreate();
  449. if (pattern == 0)
  450. return;
  451. // We are only interested in the names of the font families
  452. FcObjectSet *objectSet = FcObjectSetBuild(FC_FAMILY, NULL);
  453. if (objectSet == 0)
  454. {
  455. FcPatternDestroy(pattern);
  456. return;
  457. }
  458. // Get all available fonts and put their names into the vector
  459. FcFontSet *fontSet = FcFontList(0, pattern, objectSet);
  460. if (fontSet != 0)
  461. {
  462. int i;
  463. set<string> familySet;
  464. for (i = 0; i < fontSet->nfont; ++i)
  465. {
  466. FcChar8 *family;
  467. if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch)
  468. familySet.insert(reinterpret_cast<char*>(family));
  469. }
  470. // GRRRR, this does not work on WIN32...
  471. //families.assign(familySet.begin(), familySet.end());
  472. families.resize(familySet.size());
  473. copy(familySet.begin(), familySet.end(), families.begin());
  474. FcFontSetDestroy(fontSet);
  475. }
  476. // Cleanup
  477. FcObjectSetDestroy(objectSet);
  478. FcPatternDestroy(pattern);
  479. #else // !OSG_WITH_FONTCONFIG
  480. // Scan the font search path for fonts
  481. scanForFonts();
  482. // Put the available fonts into the vector
  483. families.reserve(_fontMap.size());
  484. FontMap::const_iterator it;
  485. for (it = _fontMap.begin(); it != _fontMap.end(); ++it)
  486. families.push_back(it->first);
  487. unique(families.begin(), families.end());
  488. #endif // !OSG_WITH_FONTCONFIG
  489. }
  490. //----------------------------------------------------------------------
  491. // Scans the font search path for fonts
  492. // Author: pdaehne
  493. //----------------------------------------------------------------------
  494. #ifndef OSG_WITH_FONTCONFIG
  495. void TextFT2Backend::scanForFonts(void)
  496. {
  497. // We scan the font directory only once
  498. if (_scanForFonts == true)
  499. {
  500. _scanForFonts = false;
  501. // Split the path list into its components
  502. string::size_type start = 0;
  503. while (true)
  504. {
  505. #ifdef _WIN32
  506. string::size_type end = _pathList.find(';', start);
  507. #else
  508. string::size_type end = _pathList.find(':', start);
  509. #endif
  510. string path = end == string::npos ? _pathList.substr(start) : _pathList.substr(start, end - start);
  511. // Remove whitespace
  512. string::size_type wsPos = path.find_first_not_of(" \t\r\n");
  513. if (wsPos != string::npos)
  514. {
  515. path.erase(0, wsPos);
  516. wsPos = path.find_last_not_of(" \t\r\n");
  517. path.erase(wsPos + 1);
  518. // Scan the directory for fonts
  519. scanDir(path);
  520. }
  521. if (end == string::npos)
  522. break;
  523. start = end + 1;
  524. }
  525. }
  526. }
  527. #endif // !OSG_WITH_FONTCONFIG
  528. //----------------------------------------------------------------------
  529. // Scans a directory and its subdirectories for fonts
  530. // Author: pdaehne
  531. //----------------------------------------------------------------------
  532. #ifndef OSG_WITH_FONTCONFIG
  533. void TextFT2Backend::scanDir(const string &path)
  534. {
  535. #ifdef _WIN32
  536. // Append a slash to the end of the path if necessary
  537. string p = path;
  538. if ((p.length() < 1) || ((p[p.length() - 1] != '/') && (p[p.length() - 1] != '\\')))
  539. p.append(1, '\\');
  540. // Try to find the first directory entry
  541. string pattern = p;
  542. pattern.append(1, '*');
  543. WIN32_FIND_DATA findFileData;
  544. HANDLE hFind = FindFirstFile(pattern.c_str(), &findFileData);
  545. if (hFind == INVALID_HANDLE_VALUE)
  546. return;
  547. while (true)
  548. {
  549. // Create the full path of the directory entry
  550. string name = findFileData.cFileName;
  551. string fullname = p;
  552. fullname.append(name);
  553. if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  554. {
  555. // Recursively scan subdirectories
  556. if ((name != ".") && (name != ".."))
  557. scanDir(fullname);
  558. }
  559. else
  560. // Try to open the file as a font
  561. checkFile(fullname);
  562. // Try to find the next directory entry
  563. if (FindNextFile(hFind, &findFileData) == FALSE)
  564. break;
  565. }
  566. // Finished
  567. FindClose(hFind);
  568. #else // !_WIN32
  569. // Open the directory
  570. DIR *dir = opendir(path.c_str());
  571. if (dir == 0)
  572. return;
  573. // Append a slash to the end of the path if necessary
  574. string p = path;
  575. if ((p.length() < 1) || (p[p.length() - 1] != '/'))
  576. p.append(1, '/');
  577. struct dirent entry, *result;
  578. while (true)
  579. {
  580. // Try to get the next directory entry
  581. if (readdir_r(dir, &entry, &result) != 0)
  582. return;
  583. if (result == 0)
  584. break;
  585. // Create the full path of the directory entry
  586. string name = entry.d_name;
  587. string fullname = p;
  588. fullname.append(name);
  589. switch (entry.d_type)
  590. {
  591. case DT_DIR:
  592. // Recursively scan subdirectories
  593. if ((name != ".") && (name != ".."))
  594. scanDir(fullname);
  595. break;
  596. case DT_REG:
  597. // Try to open the file as a font
  598. checkFile(fullname);
  599. break;
  600. default:
  601. break;
  602. }
  603. }
  604. // Finished
  605. closedir(dir);
  606. #endif // !_WIN32
  607. }
  608. #endif // !OSG_WITH_FONTCONFIG
  609. //----------------------------------------------------------------------
  610. // Checks if a file is a font file
  611. // Author: pdaehne
  612. //----------------------------------------------------------------------
  613. #ifndef OSG_WITH_FONTCONFIG
  614. void TextFT2Backend::checkFile(const string &fullname)
  615. {
  616. // Try to open the file as a font
  617. FT_Long index = 0;
  618. FT_Long numFaces = 1;
  619. while (index < numFaces)
  620. {
  621. FT_Face face;
  622. FT_Error error = FT_New_Face(_library, fullname.c_str(), index, &face);
  623. if (error)
  624. break;
  625. // We got a font - put it into the map of fonts
  626. numFaces = face->num_faces;
  627. FontInfo fontInfo;
  628. fontInfo.path = fullname;
  629. fontInfo.index = index;
  630. if (face->style_flags & FT_STYLE_FLAG_BOLD)
  631. fontInfo.style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_BOLDITALIC : TextFace::STYLE_BOLD;
  632. else
  633. fontInfo.style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_ITALIC : TextFace::STYLE_PLAIN;
  634. string family = face->family_name;
  635. //transform(family.begin(), family.end(), family.begin(), ::tolower);
  636. _fontMap.insert(FontMap::value_type(family, fontInfo));
  637. FT_Done_Face(face);
  638. ++index;
  639. }
  640. }
  641. #endif // !OSG_WITH_FONTCONFIG
  642. //----------------------------------------------------------------------
  643. // Returns information about a face
  644. // Author: pdaehne
  645. //----------------------------------------------------------------------
  646. static void getFaceInfo(FT_Face face, string &family, TextFace::Style &style)
  647. {
  648. // Determine the family name
  649. family = face->family_name;
  650. // Determine the style
  651. if (face->style_flags & FT_STYLE_FLAG_BOLD)
  652. style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_BOLDITALIC : TextFace::STYLE_BOLD;
  653. else
  654. style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_ITALIC : TextFace::STYLE_PLAIN;
  655. }
  656. //----------------------------------------------------------------------
  657. // Constructor
  658. // Author: pdaehne
  659. //----------------------------------------------------------------------
  660. TextFT2VectorFace::TextFT2VectorFace(FT_Face face)
  661. : TextVectorFace(),
  662. _face(face)
  663. {
  664. // Get information about the face
  665. getFaceInfo(_face, _family, _style);
  666. // Determine the scale factor
  667. _scale = 1.f / static_cast<Real32>(_face->ascender - _face->descender);
  668. // Determine ascent
  669. _horiAscent = static_cast<Real32>(_face->ascender) * _scale;
  670. _vertAscent = -0.5f;
  671. // Determine descent
  672. _horiDescent = static_cast<Real32>(_face->descender) * _scale;
  673. _vertDescent = 0.5f;
  674. }
  675. //----------------------------------------------------------------------
  676. // Destructor
  677. // Author: pdaehne
  678. //----------------------------------------------------------------------
  679. TextFT2VectorFace::~TextFT2VectorFace(void)
  680. {
  681. // Close the font file
  682. FT_Done_Face(_face);
  683. }
  684. //----------------------------------------------------------------------
  685. // Lays out one line of text
  686. // Author: pdaehne
  687. //----------------------------------------------------------------------
  688. void TextFT2VectorFace::layout(const wstring &text, const TextLayoutParam &param,
  689. TextLayoutResult &layoutResult)
  690. {
  691. // Initialize return values
  692. layoutResult.clear();
  693. // Do the layout depending on the direction
  694. FT_UInt previousGlyphIndex = 0;
  695. Vec2f currPos;
  696. size_t i, len = text.length();
  697. layoutResult.indices.reserve(len);
  698. layoutResult.positions.reserve(len);
  699. vector<UInt32> spaceIndices;
  700. bool justify = param.getLength(0) > 0.f;
  701. for (i = 0; i < len; ++i)
  702. {
  703. // Get glyph
  704. FT_UInt glyphIndex = FT_Get_Char_Index(_face, text[i]);
  705. const TextGlyph &glyph = getGlyph(glyphIndex);
  706. if ((justify == true) && (text[i] == ' '))
  707. spaceIndices.push_back(layoutResult.indices.size());
  708. // Calculate position
  709. Vec2f pos;
  710. if (param.horizontal == true)
  711. {
  712. if (param.leftToRight == true)
  713. {
  714. FT_Vector kerning;
  715. FT_Get_Kerning(_face, previousGlyphIndex, glyphIndex, ft_kerning_unscaled/*FT_KERNING_UNSCALED*/, &kerning);
  716. currPos[0] += static_cast<float>(kerning.x) * _scale;
  717. pos = currPos;
  718. pos[0] += glyph.getHoriBearingX();
  719. pos[1] += glyph.getHoriBearingY();
  720. currPos[0] += glyph.getHoriAdvance();
  721. }
  722. else // leftToRight == false
  723. {
  724. FT_Vector kerning;
  725. FT_Get_Kerning(_face, glyphIndex, previousGlyphIndex, ft_kerning_unscaled/*FT_KERNING_UNSCALED*/, &kerning);
  726. currPos[0] -= static_cast<float>(kerning.x) * _scale + glyph.getHoriAdvance();
  727. pos = currPos;
  728. pos[0] += glyph.getHoriBearingX();
  729. pos[1] += glyph.getHoriBearingY();
  730. }
  731. previousGlyphIndex = glyphIndex;
  732. }
  733. else // horizontal == false
  734. {
  735. if (param.topToBottom == true)
  736. {
  737. pos = currPos;
  738. pos[0] += glyph.getVertBearingX();
  739. pos[1] += glyph.getVertBearingY();
  740. currPos[1] += glyph.getVertAdvance();
  741. }
  742. else // topToBottom == false
  743. {
  744. currPos[1] -= glyph.getVertAdvance();
  745. pos = currPos;
  746. pos[0] += glyph.getVertBearingX();
  747. pos[1] += glyph.getVertBearingY();
  748. }
  749. }
  750. layoutResult.indices.push_back(glyphIndex);
  751. layoutResult.positions.push_back(pos);
  752. }
  753. // Justify the line
  754. if (justify == true)
  755. justifyLine(param, spaceIndices, currPos, layoutResult);
  756. // Adjust the origin depending on the major and the minor alignment
  757. adjustLineOrigin(param, currPos, layoutResult);
  758. // Determine text bounds / line bounds
  759. if (param.horizontal == true)
  760. layoutResult.textBounds.setValues(osgAbs(currPos.x()), _horiAscent - _horiDescent);
  761. else
  762. layoutResult.textBounds.setValues(_vertDescent - _vertAscent, osgAbs(currPos.y()));
  763. layoutResult.lineBounds.push_back(layoutResult.textBounds);
  764. }
  765. //----------------------------------------------------------------------
  766. // Helper object used by the decompose callback functions
  767. // Author: pdaehne
  768. //----------------------------------------------------------------------
  769. typedef struct UserData
  770. {
  771. Real32 scale;
  772. Vec2f offset;
  773. TextVectorGlyph::Outline &outline;
  774. inline UserData(Real32 s, const Vec2f &off, TextVectorGlyph::Outline &o)
  775. : scale(s), offset(off), outline(o)
  776. {}
  777. }
  778. UserData;
  779. //----------------------------------------------------------------------
  780. // callback function that starts a new contour
  781. // Author: pdaehne
  782. //----------------------------------------------------------------------
  783. #if ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR < 2))
  784. static int moveToFunc(FT_Vector *to, void *user)
  785. #else
  786. static int moveToFunc(const FT_Vector *to, void *user)
  787. #endif
  788. {
  789. UserData *userData = reinterpret_cast<UserData*>(user);
  790. // Check if the previous contour is valid, i.e. if it has more than two points.
  791. // When not, we simply delete the contour.
  792. if (userData->outline.empty() == false)
  793. if (userData->outline.back().size() < 3)
  794. userData->outline.erase(userData->outline.end() - 1);
  795. // We start a new contour
  796. userData->outline.push_back(TextVectorGlyph::Contour());
  797. // We have a point on the line
  798. Vec2f p(to->x, to->y);
  799. p *= userData->scale;
  800. p -= userData->offset;
  801. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
  802. // Continue
  803. return 0;
  804. }
  805. //----------------------------------------------------------------------
  806. // callback function that adds a line to the contour
  807. // Author: pdaehne
  808. //----------------------------------------------------------------------
  809. #if ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR < 2))
  810. static int lineToFunc(FT_Vector *to, void *user)
  811. #else
  812. static int lineToFunc(const FT_Vector *to, void *user)
  813. #endif
  814. {
  815. UserData *userData = reinterpret_cast<UserData*>(user);
  816. // We have a point on the line
  817. Vec2f p(to->x, to->y);
  818. p *= userData->scale;
  819. p -= userData->offset;
  820. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
  821. // Continue
  822. return 0;
  823. }
  824. //----------------------------------------------------------------------
  825. // callback function that adds a quadratic Bezier spline to the contour
  826. // Author: pdaehne
  827. //----------------------------------------------------------------------
  828. #if ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR < 2))
  829. static int conicToFunc(FT_Vector *control, FT_Vector *to, void *user)
  830. #else
  831. static int conicToFunc(const FT_Vector *control, const FT_Vector *to, void *user)
  832. #endif
  833. {
  834. UserData *userData = reinterpret_cast<UserData*>(user);
  835. // We have a control point and a point on the line
  836. Vec2f p(control->x, control->y);
  837. p *= userData->scale;
  838. p -= userData->offset;
  839. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_QUAD));
  840. p.setValues(to->x, to->y);
  841. p *= userData->scale;
  842. p -= userData->offset;
  843. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
  844. // Continue
  845. return 0;
  846. }
  847. //----------------------------------------------------------------------
  848. // callback function that adds a cubic Bezier spline to the contour
  849. // Author: pdaehne
  850. //----------------------------------------------------------------------
  851. #if ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR < 2))
  852. static int cubicToFunc(FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *user)
  853. #else
  854. static int cubicToFunc(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user)
  855. #endif
  856. {
  857. UserData *userData = reinterpret_cast<UserData*>(user);
  858. // We have two control points and a point on the line
  859. Vec2f p(control1->x, control1->y);
  860. p *= userData->scale;
  861. p -= userData->offset;
  862. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
  863. p.setValues(control2->x, control2->y);
  864. p *= userData->scale;
  865. p -= userData->offset;
  866. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
  867. p.setValues(to->x, to->y);
  868. p *= userData->scale;
  869. p -= userData->offset;
  870. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
  871. // Continue
  872. return 0;
  873. }
  874. //----------------------------------------------------------------------
  875. // Creates a new Glyph object
  876. // Author: pdaehne
  877. //----------------------------------------------------------------------
  878. auto_ptr<TextVectorGlyph> TextFT2VectorFace::createGlyph(TextGlyph::Index glyphIndex)
  879. {
  880. // We cannot create glyphs for invalid glyph indices
  881. if (glyphIndex == TextGlyph::INVALID_INDEX)
  882. return auto_ptr<TextVectorGlyph>();
  883. // Try to get the glyph
  884. FT_Error error = FT_Load_Glyph(_face, glyphIndex, FT_LOAD_NO_SCALE);
  885. if (error)
  886. return auto_ptr<TextVectorGlyph>();
  887. // We are only interested in outlines
  888. FT_GlyphSlot glyphSlot = _face->glyph;
  889. if (glyphSlot->format != ft_glyph_format_outline/*FT_GLYPH_FORMAT_OUTLINE*/)
  890. return auto_ptr<TextVectorGlyph>();
  891. // Create and return the new glyph object
  892. return auto_ptr<TextVectorGlyph>(new TextFT2VectorGlyph(glyphIndex, _scale, glyphSlot));
  893. }
  894. //----------------------------------------------------------------------
  895. // Constructor
  896. // Author: pdaehne
  897. //----------------------------------------------------------------------
  898. TextFT2VectorGlyph::TextFT2VectorGlyph(Index glyphIndex, float scale, FT_GlyphSlot glyphSlot)
  899. : TextVectorGlyph()
  900. {
  901. _glyphIndex = glyphIndex;
  902. _width = static_cast<Real32>(glyphSlot->metrics.width) * scale;
  903. _height = static_cast<Real32>(glyphSlot->metrics.height) * scale;
  904. // Determine horizontal glyph metrics
  905. _horiAdvance = static_cast<Real32>(glyphSlot->metrics.horiAdvance) * scale;
  906. _horiBearingX = static_cast<Real32>(glyphSlot->metrics.horiBearingX) * scale;
  907. _horiBearingY = static_cast<Real32>(glyphSlot->metrics.horiBearingY) * scale;
  908. // Determine vertical glyph metrics
  909. // Hmmm, there is no useful information here for vertical layout.
  910. // So we have to guess resonable values -pdaehne
  911. //_vertAdvance = -static_cast<Real32>(glyphSlot->metrics.vertAdvance) * scale;
  912. //_vertBearingX = static_cast<Real32>(glyphSlot->metrics.vertBearingX) * scale;
  913. //_vertBearingY = -static_cast<Real32>(glyphSlot->metrics.vertBearingY) * scale;
  914. _vertAdvance = -_height - 1.f / 10.f;
  915. _vertBearingX = -_width / 2.f;
  916. _vertBearingY = -1.f / 20.f;
  917. // Add the outlines to the glyph object
  918. FT_Outline_Funcs func_interface =
  919. {
  920. moveToFunc,
  921. lineToFunc,
  922. conicToFunc,
  923. cubicToFunc,
  924. 0,
  925. 0
  926. };
  927. UserData userData(scale, Vec2f(_horiBearingX, _horiBearingY), _outline);
  928. FT_Outline_Decompose(&(glyphSlot->outline), &func_interface, &userData);
  929. // Check if the last contour is valid, i.e. if it has more than two points.
  930. // When not, we simply delete the contour.
  931. if (_outline.empty() == false)
  932. if (_outline.back().size() < 3)
  933. _outline.erase(_outline.end() - 1);
  934. }
  935. //----------------------------------------------------------------------
  936. // Destructor
  937. // Author: pdaehne
  938. //----------------------------------------------------------------------
  939. TextFT2VectorGlyph::~TextFT2VectorGlyph() {}
  940. //----------------------------------------------------------------------
  941. // Constructor
  942. // Author: pdaehne
  943. //----------------------------------------------------------------------
  944. TextFT2PixmapFace::TextFT2PixmapFace(FT_Face face, UInt32 size)
  945. : TextPixmapFace(), _face(face)
  946. {
  947. // Get information about the face
  948. getFaceInfo(_face, _family, _style);
  949. // Set the size
  950. _size = size;
  951. // Determine ascent
  952. _horiAscent = static_cast<Real32>(_face->size->metrics.ascender) / 64.f;
  953. _vertAscent = -static_cast<Real32>(_size) / 2.f;
  954. // Determine descent
  955. _horiDescent = static_cast<Real32>(_face->size->metrics.descender) / 64.f;
  956. _vertDescent = static_cast<Real32>(_size) / 2.f;
  957. }
  958. //----------------------------------------------------------------------
  959. // Destructor
  960. // Author: pdaehne
  961. //----------------------------------------------------------------------
  962. TextFT2PixmapFace::~TextFT2PixmapFace()
  963. {
  964. // Close the font file
  965. FT_Done_Face(_face);
  966. }
  967. //----------------------------------------------------------------------
  968. // Lays out one line of text
  969. // Author: pdaehne
  970. //----------------------------------------------------------------------
  971. void TextFT2PixmapFace::layout(const wstring &text, const TextLayoutParam &param,
  972. TextLayoutResult &layoutResult)
  973. {
  974. // Initialize return values
  975. layoutResult.clear();
  976. // Do the layout depending on the direction
  977. FT_UInt previousGlyphIndex = 0;
  978. Vec2f currPos;
  979. size_t i, len = text.length();
  980. layoutResult.indices.reserve(len);
  981. layoutResult.positions.reserve(len);
  982. vector<UInt32> spaceIndices;
  983. bool justify = param.getLength(0) > 0.f;
  984. for (i = 0; i < len; ++i)
  985. {
  986. // Get glyph
  987. FT_UInt glyphIndex = FT_Get_Char_Index(_face, text[i]);
  988. const TextGlyph &glyph = getGlyph(glyphIndex);
  989. if ((justify == true) && (text[i] == ' '))
  990. spaceIndices.push_back(layoutResult.indices.size());
  991. // Calculate position
  992. Vec2f pos;
  993. if (param.horizontal == true)
  994. {
  995. if (param.leftToRight == true)
  996. {
  997. FT_Vector kerning;
  998. FT_Get_Kerning(_face, previousGlyphIndex, glyphIndex, ft_kerning_default/*FT_KERNING_DEFAULT*/, &kerning);
  999. currPos[0] += static_cast<float>(kerning.x) / 64.f;
  1000. pos[0] = currPos.x() + glyph.getHoriBearingX();
  1001. pos[1] = currPos.y() + glyph.getHoriBearingY();
  1002. currPos[0] += glyph.getHoriAdvance();
  1003. }
  1004. else // leftToRight == false
  1005. {
  1006. FT_Vector kerning;
  1007. FT_Get_Kerning(_face, glyphIndex, previousGlyphIndex, ft_kerning_default/*FT_KERNING_DEFAULT*/, &kerning);
  1008. currPos[0] -= static_cast<float>(kerning.x) / 64.f + glyph.getHoriAdvance();
  1009. pos[0] = currPos[0] + glyph.getHoriBearingX();
  1010. pos[1] = currPos[1] + glyph.getHoriBearingY();
  1011. }
  1012. previousGlyphIndex = glyphIndex;
  1013. }
  1014. else // horizontal == false
  1015. {
  1016. if (param.topToBottom == true)
  1017. {
  1018. pos[0] = currPos.x() + glyph.getVertBearingX();
  1019. pos[1] = currPos.y() + glyph.getVertBearingY();
  1020. currPos[1] += glyph.getVertAdvance();
  1021. }
  1022. else // topToBottom == false
  1023. {
  1024. currPos[1] -= glyph.getVertAdvance();
  1025. pos[0] = currPos.x() + glyph.getVertBearingX();
  1026. pos[1] = currPos.y() + glyph.getVertBearingY();
  1027. }
  1028. }
  1029. layoutResult.indices.push_back(glyphIndex);
  1030. layoutResult.positions.push_back(pos);
  1031. }
  1032. // Justify the line
  1033. if (justify == true)
  1034. justifyLine(param, spaceIndices, currPos, layoutResult);
  1035. // Adjust the origin depending on the major and the minor alignment
  1036. adjustLineOrigin(param, currPos, layoutResult);
  1037. // Determine text bounds / line bounds
  1038. if (param.horizontal == true)
  1039. layoutResult.textBounds.setValues(osgAbs(currPos.x()), _horiAscent - _horiDescent);
  1040. else
  1041. layoutResult.textBounds.setValues(_vertDescent - _vertAscent, osgAbs(currPos.y()));
  1042. layoutResult.lineBounds.push_back(layoutResult.textBounds);
  1043. }
  1044. //----------------------------------------------------------------------
  1045. // Creates a new Glyph object
  1046. // Author: pdaehne
  1047. //----------------------------------------------------------------------
  1048. auto_ptr<TextPixmapGlyph> TextFT2PixmapFace::createGlyph(TextGlyph::Index glyphIndex)
  1049. {
  1050. // We cannot create glyphs for invalid glyph indices
  1051. if (glyphIndex == TextGlyph::INVALID_INDEX)
  1052. return auto_ptr<TextPixmapGlyph>();
  1053. // Try to get the glyph
  1054. FT_Error error = FT_Load_Glyph(_face, glyphIndex, FT_LOAD_DEFAULT);
  1055. if (error)
  1056. return auto_ptr<TextPixmapGlyph>();
  1057. // We are only interested in outlines
  1058. FT_GlyphSlot glyphSlot = _face->glyph;
  1059. if (glyphSlot->format != ft_glyph_format_bitmap/*FT_GLYPH_FORMAT_BITMAP*/)
  1060. {
  1061. error = FT_Render_Glyph(glyphSlot, ft_render_mode_normal/*FT_RENDER_MODE_NORMAL*/);
  1062. if (error)
  1063. return auto_ptr<TextPixmapGlyph>();
  1064. }
  1065. // Create and return the new glyph object
  1066. return auto_ptr<TextPixmapGlyph>(new TextFT2PixmapGlyph(glyphIndex, this, glyphSlot));
  1067. }
  1068. //----------------------------------------------------------------------
  1069. // Constructor
  1070. // Author: pdaehne
  1071. //----------------------------------------------------------------------
  1072. TextFT2PixmapGlyph::TextFT2PixmapGlyph(Index glyphIndex, TextFT2PixmapFace *face, FT_GlyphSlot glyphSlot)
  1073. : TextPixmapGlyph()
  1074. {
  1075. _glyphIndex = glyphIndex;
  1076. _width = glyphSlot->bitmap.width;
  1077. _pitch = glyphSlot->bitmap.pitch;
  1078. _height = glyphSlot->bitmap.rows;
  1079. // Determine horizontal glyph metrics
  1080. _horiAdvance = static_cast<Real32>(glyphSlot->metrics.horiAdvance) / 64.f;
  1081. _horiBearingX = glyphSlot->bitmap_left;
  1082. _horiBearingY = glyphSlot->bitmap_top;
  1083. // Determine vertical glyph metrics
  1084. // Hmmm, there is no useful information here for vertical layout.
  1085. // So we have to guess resonable values -pdaehne
  1086. //_vertAdvance = -static_cast<Real32>(glyphSlot->metrics.vertAdvance) / 64.f;
  1087. //_vertBearingX = static_cast<int>(static_cast<float>(glyphSlot->metrics.vertBearingX) / 64.f);
  1088. //_vertBearingY = static_cast<int>(-static_cast<float>(glyphSlot->metrics.vertBearingY) / 64.f);
  1089. _vertBearingX = -static_cast<Int32>(_width >> 1);
  1090. _vertBearingY = static_cast<Int32>(-(face->getHoriAscent() - face->getHoriDescent()) / 20.f);
  1091. if (_vertBearingY > -1)
  1092. _vertBearingY = -1;
  1093. Int32 vertAdvanceOffset = _vertBearingY << 1;
  1094. _vertAdvance = -static_cast<Int32>(_height) + vertAdvanceOffset;
  1095. unsigned int size = glyphSlot->bitmap.pitch * glyphSlot->bitmap.rows;
  1096. if ((size == 0) || (glyphSlot->bitmap.buffer == 0))
  1097. _pixmap = 0;
  1098. else
  1099. {
  1100. _pixmap = new unsigned char[size];
  1101. memcpy(_pixmap, glyphSlot->bitmap.buffer, size);
  1102. flipPixmap();
  1103. }
  1104. }
  1105. //----------------------------------------------------------------------
  1106. // Destructor
  1107. // Author: pdaehne
  1108. //----------------------------------------------------------------------
  1109. TextFT2PixmapGlyph::~TextFT2PixmapGlyph() {}
  1110. //----------------------------------------------------------------------
  1111. // Constructor
  1112. // Author: pdaehne
  1113. //----------------------------------------------------------------------
  1114. TextFT2TXFFace::TextFT2TXFFace(FT_Face face, const TextTXFParam &param)
  1115. {
  1116. // Get information about the face
  1117. getFaceInfo(face, _family, _style);
  1118. // Set the size
  1119. _param = param;
  1120. // Determine ascent
  1121. _horiAscent = static_cast<Real32>(face->size->metrics.ascender) / 64.f;
  1122. _vertAscent = -0.5f;
  1123. // Determine descent
  1124. _horiDescent = static_cast<Real32>(face->size->metrics.descender) / 64.f;
  1125. _vertDescent = 0.5f;
  1126. // Determine the scale factor & adjust ascent and descent
  1127. _scale = 1.f / (_horiAscent - _horiDescent);
  1128. _horiAscent *= _scale;
  1129. _horiDescent *= _scale;
  1130. // Create all glyphs
  1131. wstring::const_iterator it;
  1132. for (it = param.getCharacters().begin(); it != param.getCharacters().end(); ++it)
  1133. {
  1134. FT_UInt glyphIndex = FT_Get_Char_Index(face, *it);
  1135. if (glyphIndex == 0)
  1136. continue;
  1137. FT_Error error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT);
  1138. if (error)
  1139. continue;
  1140. FT_GlyphSlot glyphSlot = face->glyph;
  1141. if (glyphSlot->format != ft_glyph_format_bitmap/*FT_GLYPH_FORMAT_BITMAP*/)
  1142. {
  1143. error = FT_Render_Glyph(glyphSlot, ft_render_mode_normal/*FT_RENDER_MODE_NORMAL*/);
  1144. if (error)
  1145. continue;
  1146. }
  1147. _glyphMap.insert(GlyphMap::value_type(*it, new TextFT2TXFGlyph(*it, this, _scale, face->glyph)));
  1148. }
  1149. // Calculate the positions of the glyphs on the texture
  1150. prepareTexture(param);
  1151. assert(_texture != NULL);
  1152. assert(_texture->getSize() == static_cast<UInt32>(_texture->getWidth() * _texture->getHeight()));
  1153. // Create the texture
  1154. for (it = param.getCharacters().begin(); it != param.getCharacters().end(); ++it)
  1155. {
  1156. GlyphMap::iterator gIt = _glyphMap.find(*it);
  1157. if (gIt == _glyphMap.end())
  1158. continue;
  1159. assert(gIt->second != 0);
  1160. TextTXFGlyph *glyph = gIt->second;
  1161. FT_UInt glyphIndex = FT_Get_Char_Index(face, *it);
  1162. if (glyphIndex == 0)
  1163. continue;
  1164. FT_Error error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT);
  1165. if (error)
  1166. continue;
  1167. FT_GlyphSlot glyphSlot = face->glyph;
  1168. if (glyphSlot->format != ft_glyph_format_bitmap/*FT_GLYPH_FORMAT_BITMAP*/)
  1169. {
  1170. error = FT_Render_Glyph(glyphSlot, ft_render_mode_normal/*FT_RENDER_MODE_NORMAL*/);
  1171. if (error)
  1172. continue;
  1173. }
  1174. unsigned char *src = glyphSlot->bitmap.buffer;
  1175. if (src == 0)
  1176. continue;
  1177. int bpl = glyphSlot->bitmap.pitch;
  1178. src += bpl * (glyph->getPixmapHeight() - 1);
  1179. unsigned char *src2;
  1180. UInt8 *dst = _texture->editData() + glyph->getX() + glyph->getY() * _texture->getWidth();
  1181. UInt32 dstPitch = _texture->getWidth() - glyph->getPixmapWidth();
  1182. UInt32 x, y;
  1183. for (y = 0; y < glyph->getPixmapHeight(); ++y)
  1184. {
  1185. src2 = src;
  1186. for (x = 0; x < glyph->getPixmapWidth(); ++x)
  1187. *dst++ = *src2++;
  1188. src -= bpl;
  1189. dst += dstPitch;
  1190. }
  1191. }
  1192. // Close the font file
  1193. FT_Done_Face(face);
  1194. }
  1195. //----------------------------------------------------------------------
  1196. // Destructor
  1197. // Author: pdaehne
  1198. //----------------------------------------------------------------------
  1199. TextFT2TXFFace::~TextFT2TXFFace() {}
  1200. //----------------------------------------------------------------------
  1201. // Constructor
  1202. // Author: pdaehne
  1203. //----------------------------------------------------------------------
  1204. TextFT2TXFGlyph::TextFT2TXFGlyph(Index glyphIndex, TextFT2TXFFace *face,
  1205. Real32 scale, FT_GlyphSlot glyphSlot)
  1206. : TextTXFGlyph()
  1207. {
  1208. _glyphIndex = glyphIndex;
  1209. _scale = scale;
  1210. _width = glyphSlot->bitmap.width;
  1211. _height = glyphSlot->bitmap.rows;
  1212. // Determine horizontal glyph metrics
  1213. _horiAdvance = static_cast<Real32>(glyphSlot->metrics.horiAdvance) / 64.f * _scale;
  1214. _horiBearingX = glyphSlot->bitmap_left;
  1215. _horiBearingY = glyphSlot->bitmap_top;
  1216. // Determine vertical glyph metrics
  1217. // Hmmm, there is no useful information here for vertical layout.
  1218. // So we have to guess resonable values -pdaehne
  1219. //_vertAdvance = -static_cast<Real32>(glyphSlot->metrics.vertAdvance) / 64.f * _scale;
  1220. //_vertBearingX = static_cast<int>(static_cast<float>(glyphSlot->metrics.vertBearingX) / 64.f);
  1221. //_vertBearingY = static_cast<int>(-static_cast<float>(glyphSlot->metrics.vertBearingY) / 64.f);
  1222. _vertBearingX = -static_cast<Int32>(_width >> 1);
  1223. if (glyphIndex == 32)
  1224. {
  1225. _vertBearingY = -_horiBearingX;
  1226. _vertAdvance = -_horiAdvance;
  1227. }
  1228. else
  1229. {
  1230. _vertBearingY = static_cast<Int32>(-(face->getHoriAscent() - face->getHoriDescent()) / _scale / 20.f);
  1231. if (_vertBearingY > -1)
  1232. _vertBearingY = -1;
  1233. Real32 vertAdvanceOffset = static_cast<Real32>(_vertBearingY) * 2.f * _scale;
  1234. _vertAdvance = -static_cast<Real32>(_height) * _scale + vertAdvanceOffset;
  1235. }
  1236. }
  1237. //----------------------------------------------------------------------
  1238. // Destructor
  1239. // Author: pdaehne
  1240. //----------------------------------------------------------------------
  1241. TextFT2TXFGlyph::~TextFT2TXFGlyph() {}
  1242. OSG_END_NAMESPACE
  1243. #endif // OSG_WITH_FT2