font.H

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 // OBS: THIS FILE IS NOT CURRENTLY IN USE
00027 
00028 
00029 
00030 
00031 
00032 
00033 #ifndef ARCHON_X3D_FONT_H
00034 #define ARCHON_X3D_FONT_H
00035 
00036 #include <string>
00037 #include <vector>
00038 
00039 #include <archon/util/ref.H>
00040 
00041 namespace Archon
00042 {
00043   namespace X3D
00044   {
00045     using namespace std;
00046     using namespace Utilities;
00047 
00048     struct Server;
00049 
00056     struct FontServer: virtual RefObjectBase
00057     {
00058       FontServer(Ref<Server>, vector<string> fontDirs);
00059 
00060       const BackRef<Server> server;
00061 
00062     private:
00063       vector<string> fontDirs;
00064     };
00065 
00066 
00067 
00068 
00069 
00070 
00071     namespace
00072     {
00073       struct Glyph
00074       {
00078         Vector2 size;
00079 
00085         Vector2 horizontalLowerLeft;
00086 
00090         double horizontalAdvance;
00091 
00097         Vector2 verticalLowerLeft;
00098 
00102         double verticalAdvance;
00103 
00104         Vector2 textureLowerLeft;
00105         Vector2 textureUpperRight;
00106 
00107         Glyph(Vector2 size,
00108               Vector2 horizontalLowerLeft,
00109               double horizontalAdvance,
00110               Vector2 verticalUpperRight,
00111               double verticalAdvance,
00112               Vector2 textureLowerLeft,
00113               Vector2 textureUpperRight):
00114           size(size),
00115           horizontalLowerLeft(horizontalLowerLeft),
00116           horizontalAdvance(horizontalAdvance),
00117           verticalLowerLeft(verticalLowerLeft),
00118           verticalAdvance(verticalAdvance),
00119           textureLowerLeft(textureLowerLeft),
00120           textureUpperRight(textureUpperRight) {}
00121       };
00122 
00123       struct FontFace;
00124 
00125       struct FontList
00126       {
00127         Mutex mutex;
00128 
00129         static vector<string> fontPaths;
00130         static int pixelSize;
00131 
00132         struct Entry
00133         {
00134           string plainFilePath;
00135           int plainFileIndex;
00136           FontFace *plainFace;
00137 
00138           string boldFilePath;
00139           int boldFileIndex;
00140           FontFace *boldFace;
00141 
00142           string italicFilePath;
00143           int italicFileIndex;
00144           FontFace *italicFace;
00145 
00146           string bolditalicFilePath;
00147           int bolditalicFileIndex;
00148           FontFace *bolditalicFace;
00149 
00150           Entry():
00151             plainFace(0), boldFace(0),
00152             italicFace(0), bolditalicFace(0) {}
00153         };
00154 
00155         map<string, Entry> fontFamilies;
00156 
00157         FT_Library library;
00158 
00159         bool addFace(string path, int index, FT_Face face)
00160         {
00161           string family = face->family_name;
00162 
00163           bool bold   = face->style_flags&FT_STYLE_FLAG_BOLD;
00164           bool italic = face->style_flags&FT_STYLE_FLAG_ITALIC;
00165 
00166           //string style = bold ? italic ? "bolditalic" : "bold" : italic ? "italic" : "plain";
00167           //cerr << "Found \"" << family << "\" " << style << "\n";
00168 
00169           /*
00170           cerr << "Style name       = " << face->style_name << "\n";
00171           cerr << "Number of glyphs = " << face->num_faces << "\n";
00172           cerr << "Units per EM     = " << face->units_per_EM << "\n";
00173           cerr << "Height           = " << face->height << "\n";
00174           cerr << "Ascender         = " << face->ascender << "\n";
00175           cerr << "Descender        = " << face->descender << "\n";
00176           cerr << "Num fixed sizes  = " << face->num_fixed_sizes << "\n";
00177           cerr << "Num charmaps     = " << face->num_charmaps << "\n";
00178           if(face->face_flags&FT_FACE_FLAG_SCALABLE)
00179             cerr << "                   FT_FACE_FLAG_SCALABLE\n";
00180           if(face->face_flags&FT_FACE_FLAG_FIXED_SIZES)
00181             cerr << "                   FT_FACE_FLAG_FIXED_SIZES\n";
00182           if(face->face_flags&FT_FACE_FLAG_FIXED_WIDTH)
00183             cerr << "                   FT_FACE_FLAG_FIXED_WIDTH\n";
00184           if(face->face_flags&FT_FACE_FLAG_HORIZONTAL)
00185             cerr << "                   FT_FACE_FLAG_HORIZONTAL\n";
00186           if(face->face_flags&FT_FACE_FLAG_VERTICAL)
00187             cerr << "                   FT_FACE_FLAG_VERTICAL\n";
00188           if(face->face_flags&FT_FACE_FLAG_SFNT)
00189             cerr << "                   FT_FACE_FLAG_SFNT\n";
00190           if(face->face_flags&FT_FACE_FLAG_KERNING)
00191             cerr << "                   FT_FACE_FLAG_KERNING\n";
00192           if(face->face_flags&FT_FACE_FLAG_MULTIPLE_MASTERS)
00193             cerr << "                   FT_FACE_FLAG_MULTIPLE_MASTERS\n";
00194           if(face->face_flags&FT_FACE_FLAG_GLYPH_NAMES)
00195             cerr << "                   FT_FACE_FLAG_GLYPH_NAMES\n";
00196           if(face->face_flags&FT_FACE_FLAG_EXTERNAL_STREAM)
00197             cerr << "                   FT_FACE_FLAG_EXTERNAL_STREAM\n";
00198           if(face->face_flags&FT_FACE_FLAG_FAST_GLYPHS)
00199             cerr << "                   FT_FACE_FLAG_FAST_GLYPHS\n";
00200           */
00201 
00202           Entry &entry = fontFamilies[family];
00203 
00204           if(!bold && !italic)
00205           {
00206             if(entry.plainFilePath.size()) return false;
00207             entry.plainFilePath = path;
00208             entry.plainFileIndex = index;
00209           }
00210           else if(bold && !italic)
00211           {
00212             if(entry.boldFilePath.size()) return false;
00213             entry.boldFilePath = path;
00214             entry.boldFileIndex = index;
00215           }
00216           else if(!bold && italic)
00217           {
00218             if(entry.italicFilePath.size()) return false;
00219             entry.italicFilePath = path;
00220             entry.italicFileIndex = index;
00221           }
00222           else if(bold && italic)
00223           {
00224             if(entry.bolditalicFilePath.size()) return false;
00225             entry.bolditalicFilePath = path;
00226             entry.bolditalicFileIndex = index;
00227           }
00228 
00229           return true;
00230         }
00231 
00232         FontList()
00233         {
00234           if(FT_Init_FreeType(&library))
00235             ARCHON_THROW1(ResourceException,
00236                           "Error initializing FreeType library");
00237           
00238           int n = 0;
00239 
00240           for(unsigned i=0; i<fontPaths.size(); ++i)
00241           {
00242             //cerr << "Searching for fonts in \"" << fontPaths[i] << "\"\n";
00243             vector<string> dirNames;
00244             try
00245             {
00246               dirNames = File::getDirNames(fontPaths[i]);
00247             }
00248             catch(File::ArgumentException &)
00249             {
00250               // ************************************   ISSUE A WARNING THROUGH THE SERVERS LOGGER ****************************
00251               continue;
00252             }
00253             for(unsigned j=0; j<dirNames.size(); ++j)
00254             {
00255               string name = dirNames[j];
00256               if(name == "." || name == "..") continue;
00257               string p = fontPaths[i]+"/"+name;
00258               if(File::Stat(p).getType() != File::Stat::type_regular) continue;
00259 
00260               FT_Face face;
00261               if(FT_New_Face(library, p.c_str(), 0, &face)) continue;
00262 
00263               //cerr << "Found font file \"" << p << "\"\n";
00264 
00265               if(addFace(p, 0, face)) ++n;
00266 
00267               unsigned m = face->num_faces;
00268               FT_Done_Face(face);
00269 
00270               for(unsigned k=1; k<m; ++k)
00271               {
00272                 if(FT_New_Face(library, p.c_str(), k, &face)) break;
00273                 if(addFace(p, k, face)) ++n;
00274                 FT_Done_Face(face);
00275               }
00276             }
00277           }
00278 
00279           cerr << "Found " + Archon::Utilities::Text::toString(n) +
00280             " font faces in " + Archon::Utilities::Text::toString(fontPaths.size()) +
00281             " directories\n";
00282         }
00283 
00284         FontFace *getFace(string familyName, bool bold, bool italic);
00285         FontFace *getDefaultFace();
00286       };
00287 
00288       vector<string> FontList::fontPaths;
00289       int FontList::pixelSize = 32;
00290 
00291       struct FontFace
00292       {
00293         Mutex mutex;
00294 
00295         double horizontalBottom;
00296         double horizontalTop;
00297 
00298         double verticalLeft;
00299         double verticalRight;
00300 
00301         vector<const Glyph *> glyphs;
00302 
00303         GLuint textureId;
00304 
00305         FontFace(string filePath, int faceIndex, int pixelSize)
00306         {
00307           const FontList *fontList = getFontList();
00308 
00309           FT_Face face;
00310           if(FT_New_Face(fontList->library, filePath.c_str(), faceIndex, &face))
00311             ARCHON_THROW1(ResourceException,
00312                           "Font file \"" + filePath + "\" is no longer available");
00313 
00314           if(FT_Set_Pixel_Sizes(face, 0, pixelSize))
00315             ARCHON_THROW1(InternalException,
00316                           "Error setting pixel size of font face");
00317 
00318           FT_GlyphSlot slot = face->glyph;
00319 
00320           glyphs.resize(256);
00321 
00322           // Create an image that is hopefully big enough for all the glyphs (we shoul really just add new images when needed)
00323           int imageWidth  = 16*pixelSize;
00324           int imageHeight = 16*pixelSize;
00325           Image texture(imageWidth, imageHeight, Image::components_la, 8); // Could be reduced to 1 bit per component
00326 
00327           // Clear the image to be totally transparent
00328           for(int x=0; x<imageWidth; ++x)
00329             for(int y=0; y<imageHeight; ++y)
00330               texture.setPixel(x, y, 255u, 0u);
00331 
00332           /*
00333            * Minimum vertical and horizontal distance between glyphs
00334            * in texture mesured in number of texels. This spacing is
00335            * introduced to prevent the texels from one glyph to
00336            * "bleed" into the bbox of an adjacent glyph due to the
00337            * filtering done by OpenGL.
00338            */
00339           const int textureSpacing = 4;
00340 
00341           /*
00342            * Number of texels to expand the minimum bbox of the glyph
00343            * in the texture by to get the bbox to use for the actual
00344            * texture mapping. This of cause increases the size of the
00345            * rendered quad for the glyph. The reason for expanding the
00346            * minimum bbox is to allow the filtering done by OpenGL to
00347            * work correctly at the edges of the glyph. If there were
00348            * no padding then otherwise smooth edges of the glyph would
00349            * be cut off too sharply. Note that half the size of
00350            * 'textureSpacing' will usually be optimal.
00351            */
00352           const double texturePadding = textureSpacing/2.0;
00353 
00354           int xPos = textureSpacing;
00355           int yPos = textureSpacing;
00356           int maxHeight = 0;
00357 
00358           // Load first Unicode page into texture
00359           for(unsigned i=0; i<256; ++i)
00360           {
00361             if(FT_Load_Char(face, static_cast<unsigned char>(i), FT_LOAD_RENDER))
00362               continue;
00363             if(int(slot->bitmap.pixel_mode) != 2)
00364               ARCHON_THROW1(InternalException,
00365                             "Unsupported pixel data encoding in font");
00366 
00367             // New row of glyphs in the texture
00368             if(slot->bitmap.width+textureSpacing > imageWidth - xPos)
00369             {
00370               yPos += maxHeight+textureSpacing;
00371               xPos = textureSpacing;
00372               maxHeight = 0;
00373             }
00374 
00375             if(slot->bitmap.width+textureSpacing > imageWidth - xPos ||
00376                slot->bitmap.rows+textureSpacing > imageHeight - yPos)
00377               ARCHON_THROW1(InternalException,
00378                             "All glyphs won't fit inside texture");
00379 
00380             // Copy the glyph into the texture image
00381             for(int x=0; x<slot->bitmap.width; ++x)
00382               for(int y=0; y<slot->bitmap.rows; ++y)
00383               {
00384                 unsigned l = (static_cast<unsigned char *>(slot->bitmap.buffer))
00385                   [x + y * slot->bitmap.width];
00386                 texture.setPixel(xPos+x, imageHeight-1-yPos-y, 255, l);
00387               }
00388 
00389             double linesPerTexel = face->units_per_EM/double(face->height*pixelSize);
00390 
00391             horizontalBottom = 0;
00392             horizontalTop    = pixelSize*linesPerTexel;
00393             verticalLeft     = 0;
00394             verticalRight    = pixelSize*linesPerTexel;
00395 
00396             Vector2 horizontalLowerLeft;
00397             double horizontalAdvance;
00398             Vector2 verticalLowerLeft;
00399             double verticalAdvance;
00400 
00401             if(face->face_flags&FT_FACE_FLAG_HORIZONTAL)
00402             {
00403               horizontalLowerLeft = verticalLowerLeft =
00404                 Vector2(slot->bitmap_left-texturePadding,
00405                         slot->bitmap_top-slot->bitmap.rows-texturePadding)*
00406                 linesPerTexel;
00407 
00408               horizontalAdvance = slot->advance.x/64 * linesPerTexel;
00409               verticalAdvance   = 1;
00410             }
00411             else
00412             {
00413               horizontalLowerLeft = verticalLowerLeft =
00414                 Vector2(slot->bitmap_left-texturePadding,
00415                         slot->bitmap_top-slot->bitmap.rows-texturePadding)*
00416                 linesPerTexel;
00417 
00418               horizontalAdvance = 1;
00419               verticalAdvance   = slot->advance.y/64 * linesPerTexel;
00420             }
00421 
00422             glyphs[i] =
00423               new Glyph(Vector2(slot->bitmap.width + 2*texturePadding,
00424                                 slot->bitmap.rows  + 2*texturePadding) *
00425                         linesPerTexel,
00426                         horizontalLowerLeft, horizontalAdvance,
00427                         verticalLowerLeft, verticalAdvance,
00428                         Vector2(double(xPos-texturePadding)/imageWidth,
00429                                 double(imageHeight-1-yPos-slot->bitmap.rows-texturePadding)/imageHeight),
00430                         Vector2(double(xPos+slot->bitmap.width+texturePadding)/imageWidth,
00431                                 double(imageHeight-1-yPos+texturePadding)/imageHeight));
00432 
00433             xPos += slot->bitmap.width+textureSpacing;
00434             if(slot->bitmap.rows > maxHeight) maxHeight = slot->bitmap.rows;
00435           }
00436 
00437           {
00438             string family = face->family_name;
00439             bool bold   = face->style_flags&FT_STYLE_FLAG_BOLD;
00440             bool italic = face->style_flags&FT_STYLE_FLAG_ITALIC;
00441             string style = bold ? italic ? "bolditalic" : "bold" : italic ? "italic" : "plain";
00442             texture.save(family + " " + style + ".png");
00443           }
00444 
00445           FT_Done_Face(face);
00446 
00447           {
00448             int colorMode;
00449             switch(texture.getComponentSpecifier())
00450             {
00451             case Utilities::Image::components_l:    colorMode = GL_LUMINANCE;       break;
00452             case Utilities::Image::components_la:   colorMode = GL_LUMINANCE_ALPHA; break;
00453             case Utilities::Image::components_rgb:  colorMode = GL_RGB;             break;
00454             case Utilities::Image::components_rgba: colorMode = GL_RGBA;            break;
00455             default:
00456               ARCHON_THROW1(InternalException,
00457                             "Unsuported color components");
00458             }
00459 
00460             int componentType;
00461             switch(texture.getBitsPerComponent())
00462             {
00463             case 8:  componentType = GL_UNSIGNED_BYTE;  break;
00464             case 16: componentType = GL_UNSIGNED_SHORT; break;
00465             default:
00466               ARCHON_THROW1(InternalException,
00467                             "Unsuported color component width");
00468             }
00469 
00470             glGenTextures(1, &textureId);
00471             glBindTexture(GL_TEXTURE_2D, textureId);
00472             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00473             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP);
00474             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00475             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00476             glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00477 
00478             glTexImage2D(GL_TEXTURE_2D, 0, colorMode, texture.getWidth(),
00479                          texture.getHeight(), 0, colorMode, componentType,
00480                          texture.getDataPtr());
00481           }
00482         }
00483 
00488         const Glyph *getGlyph(uchar i)
00489         {
00490           Mutex::Lock l(mutex);
00491           if(i > 255) return 0;
00492           return glyphs[i];
00493         }
00494 
00500         static FontFace *get()
00501         {
00502           FontList *fontList = getFontList();
00503           return fontList->getDefaultFace();
00504         }
00505 
00511         static FontFace *get(string familyName, bool bold, bool italic)
00512         {
00513           FontList *fontList = getFontList();
00514           return fontList->getFace(familyName, bold, italic);
00515         }
00516 
00517       private:
00518         static FontList *getFontList()
00519         {
00520           static FontList fontList;
00521           return &fontList;
00522         }
00523       };
00524     }
00525 
00526     FontFace *FontList::getDefaultFace()
00527     {
00528       FontFace *f = getFace("Times New Roman", false, false);
00529       if(f) return f;
00530       ARCHON_THROW1(InternalException,
00531                     "Could not find default font face");
00532     }
00533 
00534     FontFace *FontList::getFace(string familyName, bool bold, bool italic)
00535     {
00536       Mutex::Lock l(mutex);
00537 
00538       map<string, Entry>::iterator i = fontFamilies.find(familyName);
00539       if(i == fontFamilies.end()) return 0;
00540 
00541       if(!bold && !italic)
00542       {
00543         if(!i->second.plainFilePath.size()) return 0;
00544         if(!i->second.plainFace)
00545           i->second.plainFace =
00546             new FontFace(i->second.plainFilePath, i->second.plainFileIndex, pixelSize);
00547         return i->second.plainFace;
00548       }
00549 
00550       if(bold && !italic)
00551       {
00552         if(!i->second.boldFilePath.size()) return 0;
00553         if(!i->second.boldFace)
00554           i->second.boldFace =
00555             new FontFace(i->second.boldFilePath, i->second.boldFileIndex, pixelSize);
00556         return i->second.boldFace;
00557       }
00558 
00559       if(!bold && italic)
00560       {
00561         if(!i->second.italicFilePath.size()) return 0;
00562         if(!i->second.italicFace)
00563           i->second.italicFace =
00564             new FontFace(i->second.italicFilePath, i->second.italicFileIndex, pixelSize);
00565         return i->second.italicFace;
00566       }
00567 
00568       if(!i->second.bolditalicFilePath.size()) return 0;
00569       if(!i->second.bolditalicFace)
00570         i->second.bolditalicFace =
00571           new FontFace(i->second.bolditalicFilePath, i->second.bolditalicFileIndex, pixelSize);
00572       return i->second.bolditalicFace;
00573     }
00574 
00575 
00576 
00577   }
00578 }
00579 
00580 #endif // ARCHON_X3D_FONT_H

Generated on Sun Jul 30 22:55:49 2006 for Archon by  doxygen 1.4.4