00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00024
00026
00028 #include <SFML/Graphics/FontManager.hpp>
00029 #include <SFML/Graphics/Color.hpp>
00030 #include <SFML/Graphics/GraphicsDevice.hpp>
00031 #include <SFML/Graphics/Image.hpp>
00032 #include <SFML/Window/OpenGLCaps.hpp>
00033 #include <ft2build.h>
00034 #include FT_FREETYPE_H
00035 #include FT_GLYPH_H
00036 #include <iostream>
00037 #include <vector>
00038
00039
00040 namespace
00041 {
00045 FT_Library Library = NULL;
00046
00050 std::string GetErrorDesc(FT_Error Error)
00051 {
00052 switch (Error)
00053 {
00054
00055 case FT_Err_Cannot_Open_Resource : return "cannot open resource";
00056 case FT_Err_Unknown_File_Format : return "unknown file format";
00057 case FT_Err_Invalid_File_Format : return "broken file";
00058 case FT_Err_Invalid_Version : return "invalid FreeType version";
00059 case FT_Err_Lower_Module_Version : return "module version is too low";
00060 case FT_Err_Invalid_Argument : return "invalid argument";
00061 case FT_Err_Unimplemented_Feature : return "unimplemented feature";
00062 case FT_Err_Invalid_Table : return "broken table";
00063 case FT_Err_Invalid_Offset : return "broken offset within table";
00064
00065
00066 case FT_Err_Invalid_Glyph_Index : return "invalid glyph index";
00067 case FT_Err_Invalid_Character_Code : return "invalid character code";
00068 case FT_Err_Invalid_Glyph_Format : return "unsupported glyph image format";
00069 case FT_Err_Cannot_Render_Glyph : return "cannot render this glyph format";
00070 case FT_Err_Invalid_Outline : return "invalid outline";
00071 case FT_Err_Invalid_Composite : return "invalid composite glyph";
00072 case FT_Err_Too_Many_Hints : return "too many hints";
00073 case FT_Err_Invalid_Pixel_Size : return "invalid pixel size";
00074
00075
00076 case FT_Err_Invalid_Handle : return "invalid object handle";
00077 case FT_Err_Invalid_Library_Handle : return "invalid library handle";
00078 case FT_Err_Invalid_Driver_Handle : return "invalid module handle";
00079 case FT_Err_Invalid_Face_Handle : return "invalid face handle";
00080 case FT_Err_Invalid_Size_Handle : return "invalid size handle";
00081 case FT_Err_Invalid_Slot_Handle : return "invalid glyph slot handle";
00082 case FT_Err_Invalid_CharMap_Handle : return "invalid charmap handle";
00083 case FT_Err_Invalid_Cache_Handle : return "invalid cache manager handle";
00084 case FT_Err_Invalid_Stream_Handle : return "invalid stream handle";
00085
00086
00087 case FT_Err_Too_Many_Drivers : return "too many modules";
00088 case FT_Err_Too_Many_Extensions : return "too many extensions";
00089
00090
00091 case FT_Err_Out_Of_Memory : return "out of memory";
00092 case FT_Err_Unlisted_Object : return "unlisted object";
00093
00094
00095 case FT_Err_Cannot_Open_Stream : return "cannot open stream";
00096 case FT_Err_Invalid_Stream_Seek : return "invalid stream seek";
00097 case FT_Err_Invalid_Stream_Skip : return "invalid stream skip";
00098 case FT_Err_Invalid_Stream_Read : return "invalid stream read";
00099 case FT_Err_Invalid_Stream_Operation : return "invalid stream operation";
00100 case FT_Err_Invalid_Frame_Operation : return "invalid frame operation";
00101 case FT_Err_Nested_Frame_Access : return "nested frame access";
00102 case FT_Err_Invalid_Frame_Read : return "invalid frame read";
00103
00104
00105 case FT_Err_Raster_Uninitialized : return "raster uninitialized";
00106 case FT_Err_Raster_Corrupted : return "raster corrupted";
00107 case FT_Err_Raster_Overflow : return "raster overflow";
00108 case FT_Err_Raster_Negative_Height : return "negative height while rastering";
00109
00110
00111 case FT_Err_Too_Many_Caches : return "too many registered caches";
00112
00113
00114 case FT_Err_Invalid_Opcode : return "invalid opcode";
00115 case FT_Err_Too_Few_Arguments : return "too few arguments";
00116 case FT_Err_Stack_Overflow : return "stack overflow";
00117 case FT_Err_Code_Overflow : return "code overflow";
00118 case FT_Err_Bad_Argument : return "bad argument";
00119 case FT_Err_Divide_By_Zero : return "division by zero";
00120 case FT_Err_Invalid_Reference : return "invalid reference";
00121 case FT_Err_Debug_OpCode : return "found debug opcode";
00122 case FT_Err_ENDF_In_Exec_Stream : return "found ENDF opcode in execution stream";
00123 case FT_Err_Nested_DEFS : return "nested DEFS";
00124 case FT_Err_Invalid_CodeRange : return "invalid code range";
00125 case FT_Err_Execution_Too_Long : return "execution context too long";
00126 case FT_Err_Too_Many_Function_Defs : return "too many function definitions";
00127 case FT_Err_Too_Many_Instruction_Defs : return "too many instruction definitions";
00128 case FT_Err_Table_Missing : return "SFNT font table missing";
00129 case FT_Err_Horiz_Header_Missing : return "horizontal header (hhea) table missing";
00130 case FT_Err_Locations_Missing : return "locations (loca) table missing";
00131 case FT_Err_Name_Table_Missing : return "name table missing";
00132 case FT_Err_CMap_Table_Missing : return "character map (cmap) table missing";
00133 case FT_Err_Hmtx_Table_Missing : return "horizontal metrics (hmtx) table missing";
00134 case FT_Err_Post_Table_Missing : return "PostScript (post) table missing";
00135 case FT_Err_Invalid_Horiz_Metrics : return "invalid horizontal metrics";
00136 case FT_Err_Invalid_CharMap_Format : return "invalid character map (cmap) format";
00137 case FT_Err_Invalid_PPem : return "invalid ppem value";
00138 case FT_Err_Invalid_Vert_Metrics : return "invalid vertical metrics";
00139 case FT_Err_Could_Not_Find_Context : return "could not find context";
00140 case FT_Err_Invalid_Post_Table_Format : return "invalid PostScript (post) table format";
00141 case FT_Err_Invalid_Post_Table : return "invalid PostScript (post) table";
00142
00143
00144 case FT_Err_Syntax_Error : return "opcode syntax error";
00145 case FT_Err_Stack_Underflow : return "argument stack underflow";
00146 case FT_Err_Ignore : return "ignore";
00147
00148
00149 case FT_Err_Missing_Startfont_Field : return "`STARTFONT' field missing";
00150 case FT_Err_Missing_Font_Field : return "`FONT' field missing";
00151 case FT_Err_Missing_Size_Field : return "`SIZE' field missing";
00152 case FT_Err_Missing_Chars_Field : return "`CHARS' field missing";
00153 case FT_Err_Missing_Startchar_Field : return "`STARTCHAR' field missing";
00154 case FT_Err_Missing_Encoding_Field : return "`ENCODING' field missing";
00155 case FT_Err_Missing_Bbx_Field : return "`BBX' field missing";
00156 }
00157
00158 return "";
00159 }
00160 }
00161
00162 namespace sf_private
00163 {
00164
00165 #include <SFML/Graphics/DefaultFont.hpp>
00166
00167
00171 sfFontManager& sfFontManager::GetInstance()
00172 {
00173 static sfFontManager Instance;
00174
00175 return Instance;
00176 }
00177
00178
00182 sfFontManager::sfFontManager()
00183 {
00184
00185 FT_Error Error = FT_Init_FreeType(&Library);
00186 if (Error)
00187 {
00188 std::cerr << "Failed to initialize FreeType library (error code : " << Error << ")" << std::endl;
00189 return;
00190 }
00191
00192
00193 CreateDefaultFont();
00194 }
00195
00196
00200 sfFontManager::~sfFontManager()
00201 {
00202
00203 if (Library)
00204 FT_Done_FreeType(Library);
00205 }
00206
00207
00211 const sfFontManager::Font& sfFontManager::GetBitmapFont(const std::string& Filename, unsigned int CharSize)
00212 {
00213
00214 if (!Library)
00215 return myFonts["default"];
00216
00217
00218 if ((Filename == "") || (Filename == "default"))
00219 return myFonts["default"];
00220
00221
00222 FontTable::iterator It = myFonts.find(Filename);
00223 if ((It != myFonts.end()) && (It->second.CharSize >= CharSize))
00224 return It->second;
00225
00226
00227 int MaxSize = sfOpenGLCaps::GetMaxTextureSize();
00228 if ((int)CharSize >= MaxSize / 8) CharSize = MaxSize / 8;
00229
00230 unsigned int Left = 0;
00231 unsigned int Top = 0;
00232 unsigned int TexWidth = sfImage::GetValidTextureSize(CharSize * 8);
00233 unsigned int TexHeight = sfImage::GetValidTextureSize(CharSize * 8);
00234 std::vector<unsigned int> Tops(TexWidth, 0);
00235
00236
00237 Font CurFont;
00238 CurFont.CharSize = CharSize;
00239 CurFont.Image.Create(TexWidth, TexHeight, sfColor(0, 0, 0, 0));
00240
00241
00242 FT_Face FontFace;
00243 FT_Error Error = FT_New_Face(Library, Filename.c_str(), 0, &FontFace);
00244 if (Error)
00245 {
00246 std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00247 return myFonts["default"];
00248 }
00249
00250
00251 Error = FT_Set_Pixel_Sizes(FontFace, CharSize, CharSize);
00252 if (Error)
00253 {
00254 std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00255 return myFonts["default"];
00256 }
00257
00258
00259 sfIntRect Coords[256];
00260 for (int i = 31; i < 256; ++i)
00261 {
00262
00263 Error = FT_Load_Char(FontFace, i, FT_LOAD_DEFAULT);
00264 if (Error)
00265 {
00266 std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00267 return myFonts["default"];
00268 }
00269
00270
00271 FT_Glyph Glyph;
00272 Error = FT_Get_Glyph(FontFace->glyph, &Glyph);
00273 if (Error)
00274 {
00275 std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00276 return myFonts["default"];
00277 }
00278 FT_Glyph_To_Bitmap(&Glyph, ft_render_mode_normal, 0, 1);
00279 FT_BitmapGlyph BitmapGlyph = (FT_BitmapGlyph)Glyph;
00280 FT_Bitmap& Bitmap = BitmapGlyph->bitmap;
00281
00282
00283 if (Bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
00284 {
00285 std::cerr << "Error loading font \"" << Filename << "\" (pixel format not supported)" << std::endl;
00286 return myFonts["default"];
00287 }
00288
00289
00290 if (Left + Bitmap.width >= TexWidth)
00291 Left = 0;
00292
00293
00294 Top = Tops[Left];
00295 for (int x = 0; x < Bitmap.width; ++x)
00296 Top = std::max(Top, Tops[Left + x]);
00297
00298
00299 if (Top + Bitmap.rows >= TexHeight)
00300 {
00301 TexHeight *= 2;
00302 CurFont.Image.Resize(TexWidth, TexHeight, sfColor(0, 0, 0, 0));
00303 }
00304
00305
00306 sfIntRect& Rect = CurFont.Rect[i];
00307 Rect.Left = BitmapGlyph->left;
00308 Rect.Top = -BitmapGlyph->top;
00309 Rect.Right = Rect.Left + Bitmap.width;
00310 Rect.Bottom = Bitmap.rows - BitmapGlyph->top;
00311 CurFont.Advance[i] = FontFace->glyph->advance.x / 64;
00312
00313
00314 Coords[i] = sfIntRect(Left, Top, Left + Bitmap.width, Top + Bitmap.rows);
00315
00316
00317 const sfUint8* Pixels = Bitmap.buffer;
00318 for (int y = 0; y < Bitmap.rows; ++y)
00319 {
00320 for (int x = 0; x < Bitmap.width; ++x)
00321 {
00322 CurFont.Image.SetPixel(x + Left, y + Top, sfColor(Pixels[x], Pixels[x], Pixels[x], Pixels[x]));
00323 }
00324 Pixels += Bitmap.pitch;
00325 }
00326
00327 for (int x = 0; x < Bitmap.width; ++x)
00328 Tops[Left + x] = Top + Bitmap.rows;
00329
00330 Left += Bitmap.width;
00331 }
00332
00333
00334 for (int i = 31; i < 256; ++i)
00335 CurFont.Coord[i] = CurFont.Image.GetTexCoords(Coords[i]);
00336
00337
00338 CurFont.Image.Update();
00339
00340
00341 myFonts[Filename] = CurFont;
00342
00343 return myFonts[Filename];
00344 }
00345
00346
00350 void sfFontManager::CreateDefaultFont()
00351 {
00352 Font DefaultFont;
00353
00354
00355 DefaultFont.Image.Create(256, 512);
00356 for (int j = 0; j < 512; ++j)
00357 for (int i = 0; i < 256; ++i)
00358 {
00359 sfUint8 Lum = DefaultFontBitmap[i + j * 256];
00360 DefaultFont.Image.SetPixel(i, j, sfColor(Lum, Lum, Lum, Lum));
00361 }
00362 DefaultFont.Image.Update();
00363
00364
00365 for (int i = 0; i < 256; i++)
00366 {
00367 DefaultFont.Rect[i] = sfIntRect(DefaultFontRect[i * 4 + 0],
00368 DefaultFontRect[i * 4 + 1],
00369 DefaultFontRect[i * 4 + 2],
00370 DefaultFontRect[i * 4 + 3]);
00371 }
00372
00373
00374 for (int i = 0; i < 256; i++)
00375 {
00376 DefaultFont.Coord[i] = sfFloatRect(DefaultFontCoord[i * 4 + 0],
00377 DefaultFontCoord[i * 4 + 1],
00378 DefaultFontCoord[i * 4 + 2],
00379 DefaultFontCoord[i * 4 + 3]);
00380 }
00381
00382
00383 for (int i = 0; i < 256; i++)
00384 DefaultFont.Advance[i] = DefaultFontAdvance[i];
00385
00386
00387 DefaultFont.CharSize = DefaultFontCharSize;
00388
00389
00390 myFonts.insert(FontTable::value_type("default", DefaultFont));
00391 }
00392
00393 }