00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "CEGUIFont.h"
00027 #include "CEGUIExceptions.h"
00028 #include "CEGUISystem.h"
00029 #include "CEGUIFontManager.h"
00030 #include "CEGUIImagesetManager.h"
00031 #include "CEGUIImageset.h"
00032 #include "CEGUITexture.h"
00033 #include "CEGUILogger.h"
00034 #include "CEGUITextUtils.h"
00035 #include "CEGUIFont_xmlHandler.h"
00036 #include "CEGUIFont_implData.h"
00037 #include "CEGUIResourceProvider.h"
00038 #include "CEGUIXMLParser.h"
00039
00040 #include <ft2build.h>
00041 #include FT_FREETYPE_H
00042
00043 #include <algorithm>
00044 #include <sstream>
00045
00046
00047 namespace CEGUI
00048 {
00049
00050
00051
00052 const argb_t Font::DefaultColour = 0xFFFFFFFF;
00053 const uint Font::InterGlyphPadSpace = 2;
00054
00055
00056 const char Font::FontSchemaName[] = "Font.xsd";
00057
00058
00059
00060
00061
00062 Font::Font(const String& filename, const String& resourceGroup, FontImplData* dat)
00063 {
00064 d_antiAliased = false;
00065 d_impldat = dat;
00066 d_freetype = false;
00067 d_glyph_images = NULL;
00068
00069
00070 d_autoScale = false;
00071 setNativeResolution(Size(DefaultNativeHorzRes, DefaultNativeVertRes));
00072
00073 load(filename, resourceGroup);
00074
00075
00076 calculateStaticVertSpacing();
00077 }
00078
00079
00080
00081
00082
00083
00084
00085 Font::Font(const String& name, const String& fontname, const String& resourceGroup, uint size, uint flags, const String& glyph_set, FontImplData* dat)
00086 {
00087 d_impldat = dat;
00088 d_freetype = false;
00089 d_glyph_images = NULL;
00090
00091
00092 d_autoScale = false;
00093 setNativeResolution(Size(DefaultNativeHorzRes, DefaultNativeVertRes));
00094
00095 constructor_impl(name, fontname, resourceGroup, size, flags, glyph_set);
00096 }
00097
00098
00099
00100
00101
00102
00103
00104 Font::Font(const String& name, const String& fontname, const String& resourceGroup, uint size, uint flags, utf32 first_code_point, utf32 last_code_point, FontImplData* dat)
00105 {
00106 d_impldat = dat;
00107 d_freetype = false;
00108 d_glyph_images = NULL;
00109
00110
00111 d_autoScale = false;
00112 setNativeResolution(Size(DefaultNativeHorzRes, DefaultNativeVertRes));
00113
00114 String tmp;
00115
00116 for (utf32 cp = first_code_point; cp <= last_code_point; ++cp)
00117 {
00118 tmp += cp;
00119 }
00120
00121 constructor_impl(name, fontname, resourceGroup, size, flags, tmp);
00122 }
00123
00124
00125
00126
00127
00128
00129 Font::Font(const String& name, const String& fontname, const String& resourceGroup, uint size, uint flags, FontImplData* dat)
00130 {
00131 d_impldat = dat;
00132 d_freetype = false;
00133 d_glyph_images = NULL;
00134
00135
00136 d_autoScale = false;
00137 setNativeResolution(Size(DefaultNativeHorzRes, DefaultNativeVertRes));
00138
00139 String tmp;
00140
00141 for (utf32 cp = 32; cp <= 127; ++cp)
00142 {
00143 tmp += cp;
00144 }
00145
00146 constructor_impl(name, fontname, resourceGroup, size, flags, tmp);
00147 }
00148
00149
00150
00151
00152
00153 Font::~Font(void)
00154 {
00155 unload();
00156 delete d_impldat;
00157 }
00158
00159
00160
00161
00162
00163 float Font::getTextExtent(const String& text, float x_scale) const
00164 {
00165 float cur_extent = 0, adv_extent = 0, width;
00166
00167 size_t char_count = text.length();
00168 CodepointMap::const_iterator pos, end = d_cp_map.end();
00169
00170 for (size_t c = 0; c < char_count; ++c)
00171 {
00172 pos = d_cp_map.find(text[c]);
00173
00174 if (pos != end)
00175 {
00176 width = (pos->second.d_image->getWidth() + pos->second.d_image->getOffsetX()) * x_scale;
00177
00178 if (adv_extent + width > cur_extent)
00179 {
00180 cur_extent = adv_extent + width;
00181 }
00182
00183 adv_extent += (float)pos->second.d_horz_advance * x_scale;
00184 }
00185
00186 }
00187
00188 return ceguimax(adv_extent, cur_extent);
00189 }
00190
00191
00192
00193
00194
00195
00196 size_t Font::getCharAtPixel(const String& text, size_t start_char, float pixel, float x_scale) const
00197 {
00198 float cur_extent = 0;
00199 size_t char_count = text.length();
00200
00201
00202 if ((pixel <= 0) || (char_count <= start_char))
00203 {
00204 return start_char;
00205 }
00206
00207 CodepointMap::const_iterator pos, end = d_cp_map.end();
00208
00209 for (size_t c = start_char; c < char_count; ++c)
00210 {
00211 pos = d_cp_map.find(text[c]);
00212
00213 if (pos != end)
00214 {
00215 cur_extent += (float)pos->second.d_horz_advance * x_scale;
00216
00217 if (pixel < cur_extent)
00218 {
00219 return c;
00220 }
00221
00222 }
00223
00224 }
00225
00226 return char_count;
00227 }
00228
00229
00230
00231
00232
00233 size_t Font::drawText(const String& text, const Rect& draw_area, float z, const Rect& clip_rect, TextFormatting fmt, const ColourRect& colours, float x_scale, float y_scale) const
00234 {
00235 size_t thisCount;
00236 size_t lineCount = 0;
00237
00238 float y_base = draw_area.d_top + getBaseline(y_scale);
00239
00240 Rect tmpDrawArea(
00241 PixelAligned(draw_area.d_left),
00242 PixelAligned(draw_area.d_top),
00243 PixelAligned(draw_area.d_right),
00244 PixelAligned(draw_area.d_bottom)
00245 );
00246
00247 size_t lineStart = 0, lineEnd = 0;
00248 String currLine;
00249
00250 while (lineEnd < text.length())
00251 {
00252 if ((lineEnd = text.find_first_of('\n', lineStart)) == String::npos)
00253 {
00254 lineEnd = text.length();
00255 }
00256
00257 currLine = text.substr(lineStart, lineEnd - lineStart);
00258 lineStart = lineEnd + 1;
00259
00260 switch(fmt)
00261 {
00262 case LeftAligned:
00263 drawTextLine(currLine, Vector3(tmpDrawArea.d_left, y_base, z), clip_rect, colours, x_scale, y_scale);
00264 thisCount = 1;
00265 y_base += getLineSpacing(y_scale);
00266 break;
00267
00268 case RightAligned:
00269 drawTextLine(currLine, Vector3(tmpDrawArea.d_right - getTextExtent(currLine, x_scale), y_base, z), clip_rect, colours, x_scale, y_scale);
00270 thisCount = 1;
00271 y_base += getLineSpacing(y_scale);
00272 break;
00273
00274 case Centred:
00275 drawTextLine(currLine, Vector3(PixelAligned(tmpDrawArea.d_left + ((tmpDrawArea.getWidth() - getTextExtent(currLine, x_scale)) / 2.0f)), y_base, z), clip_rect, colours, x_scale, y_scale);
00276 thisCount = 1;
00277 y_base += getLineSpacing(y_scale);
00278 break;
00279
00280 case Justified:
00281
00282 drawTextLineJustified(currLine, draw_area, Vector3(tmpDrawArea.d_left, y_base, z), clip_rect, colours, x_scale, y_scale);
00283 thisCount = 1;
00284 y_base += getLineSpacing(y_scale);
00285 break;
00286
00287 case WordWrapLeftAligned:
00288 thisCount = drawWrappedText(currLine, tmpDrawArea, z, clip_rect, LeftAligned, colours, x_scale, y_scale);
00289 tmpDrawArea.d_top += thisCount * getLineSpacing(y_scale);
00290 break;
00291
00292 case WordWrapRightAligned:
00293 thisCount = drawWrappedText(currLine, tmpDrawArea, z, clip_rect, RightAligned, colours, x_scale, y_scale);
00294 tmpDrawArea.d_top += thisCount * getLineSpacing(y_scale);
00295 break;
00296
00297 case WordWrapCentred:
00298 thisCount = drawWrappedText(currLine, tmpDrawArea, z, clip_rect, Centred, colours, x_scale, y_scale);
00299 tmpDrawArea.d_top += thisCount * getLineSpacing(y_scale);
00300 break;
00301
00302 case WordWrapJustified:
00303
00304 thisCount = drawWrappedText(currLine, tmpDrawArea, z, clip_rect, Justified, colours, x_scale, y_scale);
00305 tmpDrawArea.d_top += thisCount * getLineSpacing(y_scale);
00306 break;
00307
00308 default:
00309 throw InvalidRequestException((utf8*)"Font::drawText - Unknown or unsupported TextFormatting value specified.");
00310 }
00311
00312 lineCount += thisCount;
00313
00314 }
00315
00316
00317 return ceguimax(lineCount, (size_t)1);
00318 }
00319
00320
00321
00322
00323
00324 void Font::defineFontGlyphs(const String& glyph_set)
00325 {
00326 d_glyphset = glyph_set;
00327 defineFontGlyphs_impl();
00328
00329 Logger::getSingleton().logEvent("Font '" + d_name + "' now has the following glyphs defined: '" + d_glyphset + "'.", Informative);
00330 }
00331
00332
00333
00334
00335
00336
00337 uint Font::getRequiredTextureSize(const String& glyph_set)
00338 {
00339 d_maxGlyphHeight = 0;
00340
00341 uint texSize = 32;
00342 uint width;
00343
00344 uint cur_x = 0;
00345 uint cur_y = d_maxGlyphHeight;
00346
00347 uint glyph_set_length = static_cast<uint>(glyph_set.length());
00348
00349 for (uint i = 0; i < glyph_set_length; ++i)
00350 {
00351
00352 if (FT_Load_Char(d_impldat->fontFace, glyph_set[i], FT_LOAD_RENDER|(d_antiAliased ? 0 : FT_LOAD_MONOCHROME)))
00353 {
00354
00355 continue;
00356 }
00357
00358
00359 if ((uint)d_impldat->fontFace->glyph->bitmap.rows + InterGlyphPadSpace > d_maxGlyphHeight)
00360 {
00361 d_maxGlyphHeight = d_impldat->fontFace->glyph->bitmap.rows + InterGlyphPadSpace;
00362 cur_y = (i + 1) * d_maxGlyphHeight;
00363 }
00364
00365 width = d_impldat->fontFace->glyph->bitmap.width + InterGlyphPadSpace;
00366 cur_x += width;
00367
00368
00369 if (cur_x >= texSize)
00370 {
00371 cur_x = width;
00372 cur_y += d_maxGlyphHeight;
00373
00374 if (cur_y >= texSize)
00375 {
00376
00377 texSize *= 2;
00378 cur_x = 0;
00379 cur_y = d_maxGlyphHeight;
00380 i = (uint)-1;
00381 }
00382
00383 }
00384
00385 }
00386
00387 return texSize;
00388 }
00389
00390
00391
00392
00393
00394
00395 void Font::createFontGlyphSet(const String& glyph_set, uint size, argb_t* buffer)
00396 {
00397 String imageName;
00398 Rect rect;
00399 Point offset;
00400
00401 FT_GlyphSlot glyph = d_impldat->fontFace->glyph;
00402
00403 d_max_bearingY = 0;
00404
00405 size_t glyph_set_length = glyph_set.length();
00406 uint cur_x = 0;
00407 uint cur_y = 0;
00408 uint width;
00409
00410 for (uint i = 0; i < glyph_set_length; ++i)
00411 {
00412
00413 if (FT_Load_Char(d_impldat->fontFace, glyph_set[i], FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT|
00414 (d_antiAliased ? FT_LOAD_TARGET_NORMAL : FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO)))
00415 {
00416
00417 std::stringstream err;
00418 err << "Font::createFontGlyphSet - Failed to load glyph for codepoint: ";
00419 err << static_cast<unsigned int>(glyph_set[i]);
00420 Logger::getSingleton().logEvent(err.str(), Errors);
00421
00422 continue;
00423 }
00424
00425 width = glyph->bitmap.width + InterGlyphPadSpace;
00426
00427
00428 if (cur_x + width >= size)
00429 {
00430 cur_x = 0;
00431 cur_y += d_maxGlyphHeight;
00432 }
00433
00434
00435 argb_t* dest_buff = buffer + (cur_y * size) + cur_x;
00436
00437
00438 drawGlyphToBuffer(dest_buff, size);
00439
00440
00441 imageName = glyph_set[i];
00442 rect.d_left = (float)cur_x;
00443 rect.d_top = (float)cur_y;
00444 rect.d_right = (float)(cur_x + width - InterGlyphPadSpace);
00445 rect.d_bottom = (float)(cur_y + d_maxGlyphHeight - InterGlyphPadSpace);
00446
00447 offset.d_x = (float)(glyph->metrics.horiBearingX >> 6);
00448 offset.d_y = -(float)(glyph->metrics.horiBearingY >> 6);
00449
00450 d_glyph_images->defineImage(imageName, rect, offset);
00451
00452 cur_x += width;
00453
00454
00455
00456
00457
00458
00459
00460
00461 glyphDat dat;
00462 dat.d_image = &d_glyph_images->getImage(imageName);
00463 dat.d_horz_advance = glyph->advance.x >> 6;
00464 d_cp_map[glyph_set[i]] = dat;
00465 }
00466
00467 }
00468
00469
00470
00471
00472
00473
00474 void Font::createFontGlyphSet(utf32 first_code_point, utf32 last_code_point, uint size, argb_t* buffer)
00475 {
00476 String tmp;
00477
00478 for (utf32 cp = first_code_point; cp <=last_code_point; ++cp)
00479 {
00480 tmp += cp;
00481 }
00482
00483 createFontGlyphSet(tmp, size, buffer);
00484 }
00485
00486
00487
00488
00489
00490
00491
00492 uint Font::getRequiredTextureSize(utf32 first_code_point, utf32 last_code_point)
00493 {
00494 String tmp;
00495
00496 for (utf32 cp = first_code_point; cp <=last_code_point; ++cp)
00497 {
00498 tmp += cp;
00499 }
00500
00501 return getRequiredTextureSize(tmp);
00502 }
00503
00504
00505
00506
00507
00508 void Font::defineFontGlyphs(utf32 first_code_point, utf32 last_code_point)
00509 {
00510 String tmp;
00511
00512 for (utf32 cp = first_code_point; cp <=last_code_point; ++cp)
00513 {
00514 tmp += cp;
00515 }
00516
00517 defineFontGlyphs(tmp);
00518 }
00519
00520
00521
00522
00523
00524 void Font::drawGlyphToBuffer(argb_t* buffer, uint buf_width)
00525 {
00526 FT_Bitmap* glyph_bitmap = &d_impldat->fontFace->glyph->bitmap;
00527
00528 for (int i = 0; i < glyph_bitmap->rows; ++i)
00529 {
00530 for (int j = 0; j < glyph_bitmap->width; ++j)
00531 {
00532 switch (glyph_bitmap->pixel_mode)
00533 {
00534 case FT_PIXEL_MODE_GRAY:
00535 {
00536 uchar* bytebuff = reinterpret_cast<uchar*>(&buffer[j]);
00537 *bytebuff++ = 0xFF;
00538 *bytebuff++ = 0xFF;
00539 *bytebuff++ = 0xFF;
00540 *bytebuff = glyph_bitmap->buffer[(i * glyph_bitmap->pitch) + j];
00541 }
00542 break;
00543
00544 case FT_PIXEL_MODE_MONO:
00545 buffer[j] = ((glyph_bitmap->buffer[(i * glyph_bitmap->pitch) + j / 8] << (j % 8)) & 0x80) ? 0xFFFFFFFF : 0x00000000;
00546 break;
00547
00548 default:
00549 throw InvalidRequestException((utf8*)"Font::drawGlyphToBuffer - The glyph could not be drawn because the pixel mode is unsupported.");
00550 break;
00551 }
00552
00553 }
00554
00555 buffer += buf_width;
00556 }
00557
00558 }
00559
00560
00561
00562
00563
00564 size_t Font::drawWrappedText(const String& text, const Rect& draw_area, float z, const Rect& clip_rect, TextFormatting fmt, const ColourRect& colours, float x_scale, float y_scale) const
00565 {
00566 size_t line_count = 0;
00567 Rect dest_area(draw_area);
00568 float wrap_width = draw_area.getWidth();
00569
00570 String whitespace = TextUtils::DefaultWhitespace;
00571 String thisLine, thisWord;
00572 size_t currpos = 0;
00573
00574
00575 currpos += getNextWord(text, currpos, thisLine);
00576
00577
00578 while (String::npos != text.find_first_not_of(whitespace, currpos)) {
00579
00580 currpos += getNextWord(text, currpos, thisWord);
00581
00582
00583 if ((getTextExtent(thisLine, x_scale) + getTextExtent(thisWord, x_scale)) > wrap_width) {
00584
00585 line_count += drawText(thisLine, dest_area, z, clip_rect, fmt, colours, x_scale, y_scale);
00586
00587
00588 thisWord = thisWord.substr(thisWord.find_first_not_of(whitespace));
00589
00590
00591 thisLine.clear();
00592
00593
00594 dest_area.d_top += getLineSpacing(y_scale);
00595 }
00596
00597
00598 thisLine += thisWord;
00599 }
00600
00601
00602 TextFormatting last_fmt = (fmt == Justified ? LeftAligned : fmt);
00603
00604 line_count += drawText(thisLine, dest_area, z, clip_rect, last_fmt, colours, x_scale, y_scale);
00605
00606 return line_count;
00607 }
00608
00609
00610
00611
00612
00613 size_t Font::getNextWord(const String& in_string, size_t start_idx, String& out_string) const
00614 {
00615 out_string = TextUtils::getNextWord(in_string, start_idx, TextUtils::DefaultWrapDelimiters);
00616
00617 return out_string.length();
00618 }
00619
00620
00621
00622
00623
00624 void Font::drawTextLine(const String& text, const Vector3& position, const Rect& clip_rect, const ColourRect& colours, float x_scale, float y_scale) const
00625 {
00626 Vector3 cur_pos(position);
00627
00628 float base_y = position.d_y;
00629
00630 size_t char_count = text.length();
00631 CodepointMap::const_iterator pos, end = d_cp_map.end();
00632
00633 for (size_t c = 0; c < char_count; ++c)
00634 {
00635 pos = d_cp_map.find(text[c]);
00636
00637 if (pos != end)
00638 {
00639 const Image* img = pos->second.d_image;
00640 cur_pos.d_y = base_y - (img->getOffsetY() - img->getOffsetY() * y_scale);
00641 Size sz(img->getWidth() * x_scale, img->getHeight() * y_scale);
00642 img->draw(cur_pos, sz, clip_rect, colours);
00643 cur_pos.d_x += (float)pos->second.d_horz_advance * x_scale;
00644 }
00645
00646 }
00647
00648 }
00649
00650
00651
00652
00653
00654 void Font::drawTextLineJustified(const String& text, const Rect& draw_area, const Vector3& position, const Rect& clip_rect, const ColourRect& colours, float x_scale, float y_scale) const
00655 {
00656 Vector3 cur_pos(position);
00657
00658 float base_y = position.d_y;
00659
00660
00661 float lost_space = getFormattedTextExtent(text, draw_area, Justified, x_scale) - getTextExtent(text, x_scale);
00662
00663 size_t char_count = text.length();
00664 CodepointMap::const_iterator pos, end = d_cp_map.end();
00665
00666
00667 uint space_count = 0;
00668 size_t c;
00669 for (c = 0; c < char_count; ++c)
00670 if ((text[c] == ' ') || (text[c] == '\t')) ++space_count;
00671
00672
00673 float shared_lost_space = 0.0;
00674 if (space_count > 0) shared_lost_space = lost_space / (float)space_count;
00675
00676 for (c = 0; c < char_count; ++c)
00677 {
00678 pos = d_cp_map.find(text[c]);
00679
00680 if (pos != end)
00681 {
00682 const Image* img = pos->second.d_image;
00683 cur_pos.d_y = base_y - (img->getOffsetY() - img->getOffsetY() * y_scale);
00684 Size sz(img->getWidth() * x_scale, img->getHeight() * y_scale);
00685 img->draw(cur_pos, sz, clip_rect, colours);
00686 cur_pos.d_x += (float)pos->second.d_horz_advance * x_scale;
00687
00688 if ((text[c] == ' ') || (text[c] == '\t')) cur_pos.d_x += shared_lost_space;
00689 }
00690
00691 }
00692
00693 }
00694
00695
00696
00697
00698
00699 void Font::constructor_impl(const String& name, const String& fontname, const String& resourceGroup, uint size, uint flags, const String& glyph_set)
00700 {
00701 ImagesetManager& ismgr = ImagesetManager::getSingleton();
00702
00703
00704 d_antiAliased = (flags == NoAntiAlias) ? false : true;
00705
00706
00707 d_glyph_images = ismgr.createImageset(name + "_auto_glyph_images", System::getSingleton().getRenderer()->createTexture());
00708
00709 uint horzdpi = System::getSingleton().getRenderer()->getHorzScreenDPI();
00710 uint vertdpi = System::getSingleton().getRenderer()->getVertScreenDPI();
00711 String errMsg;
00712
00713 System::getSingleton().getResourceProvider()->loadRawDataContainer(fontname, d_impldat->fontData, resourceGroup);
00714
00715
00716 if (FT_New_Memory_Face(d_impldat->library, d_impldat->fontData.getDataPtr(),
00717 (FT_Long)d_impldat->fontData.getSize(), 0, &d_impldat->fontFace) == 0)
00718 {
00719
00720 if (d_impldat->fontFace->charmap != NULL)
00721 {
00722 try
00723 {
00724 d_glyphset = glyph_set;
00725 d_name = name;
00726 d_freetype = true;
00727 createFontFromFT_Face(size, horzdpi, vertdpi);
00728 return;
00729 }
00730 catch(...)
00731 {
00732 ismgr.destroyImageset(d_glyph_images);
00733 d_glyph_images = NULL;
00734
00735 FT_Done_Face(d_impldat->fontFace);
00736 d_freetype = false;
00737
00738
00739 throw;
00740 }
00741
00742 }
00743
00744 else
00745 {
00746 FT_Done_Face(d_impldat->fontFace);
00747 d_freetype = false;
00748
00749 errMsg = (utf8*)"Font::constructor_impl - The source font '" + fontname +"' does not have a Unicode charmap, and cannot be used.";
00750 }
00751
00752 }
00753
00754 else
00755 {
00756 errMsg = (utf8*)"Font::constructor_impl - An error occurred while trying to create a FreeType face from source font '" + fontname + "'.";
00757 }
00758
00759
00760 ismgr.destroyImageset(d_glyph_images);
00761
00762 throw GenericException(errMsg);
00763 }
00764
00765
00766
00767
00768
00769 void Font::load(const String& filename, const String& resourceGroup)
00770 {
00771
00772 unload();
00773
00774 if (filename.empty() || (filename == (utf8*)""))
00775 {
00776 throw InvalidRequestException((utf8*)"Font::load - Filename supplied for Font loading must be valid");
00777 }
00778
00779
00780 Font_xmlHandler handler(this);
00781
00782
00783 try
00784 {
00785 System::getSingleton().getXMLParser()->parseXMLFile(handler, filename, FontSchemaName, resourceGroup);
00786 }
00787 catch(...)
00788 {
00789 unload();
00790
00791 Logger::getSingleton().logEvent("Font::load - loading of Font from file '" + filename +"' failed.", Errors);
00792 throw;
00793 }
00794
00795 }
00796
00797
00798
00799
00800
00801
00802 void Font::unload(void)
00803 {
00804 d_cp_map.clear();
00805
00806
00807 if (d_glyph_images != NULL)
00808 {
00809 ImagesetManager::getSingleton().destroyImageset(d_glyph_images);
00810 d_glyph_images = NULL;
00811 }
00812
00813
00814 if (d_freetype)
00815 {
00816 FT_Done_Face(d_impldat->fontFace);
00817 d_freetype = false;
00818 }
00819
00820 System::getSingleton().getResourceProvider()->unloadRawDataContainer(d_impldat->fontData);
00821
00822 }
00823
00824
00825
00826
00827
00828 void Font::defineFontGlyphs_impl(void)
00829 {
00830
00831 if (!d_freetype)
00832 {
00833 throw InvalidRequestException((utf8*)"Font::defineFontGlyphs_impl - operation not supported on bitmap based fonts.");
00834 }
00835
00836 uint texture_size = getRequiredTextureSize(d_glyphset);
00837
00838
00839 if (texture_size > System::getSingleton().getRenderer()->getMaxTextureSize())
00840 {
00841 throw RendererException((utf8*)"Font::defineFontGlyphs_impl - operation requires a texture larger than the supported maximum.");
00842 }
00843
00844
00845 argb_t* mem_buffer;
00846
00847 try
00848 {
00849 mem_buffer = new argb_t[texture_size * texture_size];
00850 }
00851 catch (std::bad_alloc)
00852 {
00853 throw MemoryException((utf8*)"Font::defineFontGlyphs_impl - failed to allocate required memory buffer.");
00854 }
00855
00856
00857 memset(mem_buffer, 0, ((texture_size * texture_size) * sizeof(argb_t)));
00858
00859
00860 d_cp_map.clear();
00861 d_glyph_images->undefineAllImages();
00862
00863
00864 createFontGlyphSet(d_glyphset, texture_size, mem_buffer);
00865
00866
00867 d_glyph_images->getTexture()->loadFromMemory(mem_buffer, texture_size, texture_size);
00868
00869 delete[] mem_buffer;
00870
00871 d_lineHeight = (float)d_maxGlyphHeight;
00872
00873
00874 d_max_bearingY = ((float)d_impldat->fontFace->ascender / (float)d_impldat->fontFace->units_per_EM) * (float)d_impldat->fontFace->size->metrics.y_ppem;
00875 d_lineSpacing = ((float)d_impldat->fontFace->height / (float)d_impldat->fontFace->units_per_EM) * (float)d_impldat->fontFace->size->metrics.y_ppem;
00876 }
00877
00878
00879
00880
00881
00882 void Font::calculateStaticVertSpacing(void)
00883 {
00884 if (!d_freetype)
00885 {
00886 float scale = d_autoScale ? d_vertScaling : 1.0f;
00887
00888 d_lineHeight = 0;
00889 d_max_bearingY = 0;
00890
00891 CodepointMap::iterator pos = d_cp_map.begin(), end = d_cp_map.end();
00892
00893 for (;pos != end; ++pos)
00894 {
00895 const Image* img = pos->second.d_image;
00896
00897 if (-img->getOffsetY() > d_max_bearingY)
00898 d_max_bearingY = -img->getOffsetY();
00899
00900 if (img->getHeight() > d_lineHeight)
00901 d_lineHeight = img->getHeight();
00902 }
00903
00904 d_max_bearingY *= scale;
00905 d_lineHeight *= scale;
00906 d_lineSpacing = d_lineHeight;
00907 d_maxGlyphHeight = static_cast<uint>(d_lineHeight);
00908 }
00909
00910 }
00911
00912
00913
00914
00915
00916 void Font::setNativeResolution(const Size& size)
00917 {
00918 d_nativeHorzRes = size.d_width;
00919 d_nativeVertRes = size.d_height;
00920
00921
00922 if ((!d_freetype) && (d_glyph_images != NULL))
00923 {
00924 d_glyph_images->setNativeResolution(size);
00925 }
00926
00927
00928 notifyScreenResolution(System::getSingleton().getRenderer()->getSize());
00929 }
00930
00931
00932
00933
00934
00935 void Font::notifyScreenResolution(const Size& size)
00936 {
00937
00938
00939 if (d_glyph_images)
00940 {
00941 d_glyph_images->notifyScreenResolution(size);
00942 }
00943
00944 d_horzScaling = size.d_width / d_nativeHorzRes;
00945 d_vertScaling = size.d_height / d_nativeVertRes;
00946
00947 if (d_autoScale)
00948 {
00949 updateFontScaling();
00950 }
00951
00952 }
00953
00954
00955
00956
00957
00958 void Font::setAutoScalingEnabled(bool setting)
00959 {
00960 if (setting != d_autoScale)
00961 {
00962 if ((!d_freetype) && (d_glyph_images != NULL))
00963 {
00964 d_glyph_images->setAutoScalingEnabled(setting);
00965 }
00966
00967 d_autoScale = setting;
00968 updateFontScaling();
00969 }
00970
00971 }
00972
00973
00974
00975
00976
00977 void Font::updateFontScaling(void)
00978 {
00979 if (d_freetype)
00980 {
00981 uint hdpi = System::getSingleton().getRenderer()->getHorzScreenDPI();
00982 uint vdpi = System::getSingleton().getRenderer()->getVertScreenDPI();
00983
00984 createFontFromFT_Face(d_ptSize, hdpi, vdpi);
00985 }
00986
00987 else
00988 {
00989 float hscale = d_autoScale ? d_horzScaling : 1.0f;
00990
00991
00992 CodepointMap::iterator pos = d_cp_map.begin(), end = d_cp_map.end();
00993 for (; pos != end; ++pos)
00994 {
00995 pos->second.d_horz_advance = (uint)(((float)pos->second.d_horz_advance_unscaled) * hscale);
00996 }
00997
00998
00999 calculateStaticVertSpacing();
01000 }
01001
01002 }
01003
01004
01005
01006
01007
01008
01009 void Font::createFontFromFT_Face(uint size, uint horzDpi, uint vertDpi)
01010 {
01011 if (d_autoScale)
01012 {
01013 horzDpi = (uint)(((float)horzDpi) * d_horzScaling);
01014 vertDpi = (uint)(((float)vertDpi) * d_vertScaling);
01015 }
01016
01017 d_ptSize = size;
01018
01019 if (FT_Set_Char_Size(d_impldat->fontFace, 0, d_ptSize * 64, horzDpi, vertDpi) == 0)
01020 {
01021 defineFontGlyphs_impl();
01022 }
01023
01024 else
01025 {
01026 throw GenericException((utf8*)"Font::createFontFromFT_Face - An error occurred while creating a source font with the requested size.");
01027 }
01028
01029 }
01030
01031
01032
01033
01034
01035 size_t Font::getFormattedLineCount(const String& text, const Rect& format_area, TextFormatting fmt, float x_scale) const
01036 {
01037
01038 if ((fmt == LeftAligned) || (fmt == Centred) || (fmt == RightAligned) || (fmt == Justified))
01039 {
01040 return std::count(text.begin(), text.end(), static_cast<utf8>('\n')) + 1;
01041 }
01042
01043
01044 size_t lineStart = 0, lineEnd = 0;
01045 String sourceLine;
01046
01047 float wrap_width = format_area.getWidth();
01048 String whitespace = TextUtils::DefaultWhitespace;
01049 String thisLine, thisWord;
01050 size_t line_count = 0, currpos = 0;
01051
01052 while (lineEnd < text.length())
01053 {
01054 if ((lineEnd = text.find_first_of('\n', lineStart)) == String::npos)
01055 {
01056 lineEnd = text.length();
01057 }
01058
01059 sourceLine = text.substr(lineStart, lineEnd - lineStart);
01060 lineStart = lineEnd + 1;
01061
01062
01063 currpos = getNextWord(sourceLine, 0, thisLine);
01064
01065
01066 while (String::npos != sourceLine.find_first_not_of(whitespace, currpos))
01067 {
01068
01069 currpos += getNextWord(sourceLine, currpos, thisWord);
01070
01071
01072 if ((getTextExtent(thisLine, x_scale) + getTextExtent(thisWord, x_scale)) > wrap_width)
01073 {
01074
01075 line_count++;
01076
01077
01078 thisWord = thisWord.substr(thisWord.find_first_not_of(whitespace));
01079
01080
01081 thisLine.clear();
01082 }
01083
01084
01085 thisLine += thisWord;
01086 }
01087
01088
01089 line_count++;
01090 }
01091
01092 return line_count;
01093 }
01094
01095
01096
01097
01098
01099 bool Font::isAntiAliased(void) const
01100 {
01101 return d_freetype ? d_antiAliased : false;
01102 }
01103
01104
01105
01106
01107
01108 void Font::setAntiAliased(bool setting)
01109 {
01110 if (d_freetype && (d_antiAliased != setting))
01111 {
01112 d_antiAliased = setting;
01113
01114
01115 createFontFromFT_Face(d_ptSize, System::getSingleton().getRenderer()->getHorzScreenDPI(), System::getSingleton().getRenderer()->getVertScreenDPI());
01116 }
01117
01118 }
01119
01120
01121
01122
01123
01124 float Font::getFormattedTextExtent(const String& text, const Rect& format_area, TextFormatting fmt, float x_scale) const
01125 {
01126 float lineWidth;
01127 float widest = 0;
01128
01129 size_t lineStart = 0, lineEnd = 0;
01130 String currLine;
01131
01132 while (lineEnd < text.length())
01133 {
01134 if ((lineEnd = text.find_first_of('\n', lineStart)) == String::npos)
01135 {
01136 lineEnd = text.length();
01137 }
01138
01139 currLine = text.substr(lineStart, lineEnd - lineStart);
01140 lineStart = lineEnd + 1;
01141
01142 switch(fmt)
01143 {
01144 case Centred:
01145 case RightAligned:
01146 case LeftAligned:
01147 lineWidth = getTextExtent(currLine, x_scale);
01148 break;
01149
01150 case Justified:
01151
01152 lineWidth = ceguimax(format_area.getWidth(), getTextExtent(currLine, x_scale));
01153 break;
01154
01155 case WordWrapLeftAligned:
01156 case WordWrapRightAligned:
01157 case WordWrapCentred:
01158 lineWidth = getWrappedTextExtent(currLine, format_area.getWidth(), x_scale);
01159 break;
01160
01161 case WordWrapJustified:
01162
01163 lineWidth = ceguimax(format_area.getWidth(), getWrappedTextExtent(currLine, format_area.getWidth(), x_scale));
01164 break;
01165
01166 default:
01167 throw InvalidRequestException((utf8*)"Font::getFormattedTextExtent - Unknown or unsupported TextFormatting value specified.");
01168 }
01169
01170 if (lineWidth > widest)
01171 {
01172 widest = lineWidth;
01173 }
01174
01175 }
01176
01177 return widest;
01178 }
01179
01180
01181
01182
01183
01184 float Font::getWrappedTextExtent(const String& text, float wrapWidth, float x_scale) const
01185 {
01186 String whitespace = TextUtils::DefaultWhitespace;
01187 String thisWord;
01188 size_t currpos;
01189 float lineWidth, wordWidth;
01190 float widest = 0;
01191
01192
01193 currpos = getNextWord(text, 0, thisWord);
01194 lineWidth = getTextExtent(thisWord, x_scale);
01195
01196
01197 while (String::npos != text.find_first_not_of(whitespace, currpos)) {
01198
01199 currpos += getNextWord(text, currpos, thisWord);
01200 wordWidth = getTextExtent(thisWord, x_scale);
01201
01202
01203 if ((lineWidth + wordWidth) > wrapWidth) {
01204
01205 if (lineWidth > widest)
01206 {
01207 widest = lineWidth;
01208 }
01209
01210
01211 thisWord = thisWord.substr(thisWord.find_first_not_of(whitespace));
01212 wordWidth = getTextExtent(thisWord, x_scale);
01213
01214
01215 lineWidth = 0;
01216 }
01217
01218
01219 lineWidth += wordWidth;
01220 }
01221
01222 if (lineWidth > widest)
01223 {
01224 widest = lineWidth;
01225 }
01226
01227 return widest;
01228 }
01229
01230
01231
01232
01233
01234
01235 const String& Font::getAvailableGlyphs(void) const
01236 {
01237 return d_glyphset;
01238 }
01239
01240
01241
01242
01243
01244 uint Font::getPointSize(void) const
01245 {
01246 if (d_freetype)
01247 {
01248 return d_ptSize;
01249 }
01250 else
01251 {
01252 throw InvalidRequestException("Font::getPointSize - unable to return point size for a static (bitmap based) font.");
01253 }
01254 }
01255
01256
01257
01258
01259
01260 void Font::writeXMLToStream(OutStream& out_stream) const
01261 {
01262
01263 out_stream << "<Font Name=\"" << d_name << "\" Filename=\"" << d_sourceFilename << "\" ";
01264
01265 if (d_freetype)
01266 out_stream << "Size=\"" << d_ptSize << "\" ";
01267
01268 if (d_nativeHorzRes != DefaultNativeHorzRes)
01269 out_stream << "NativeHorzRes=\"" << static_cast<uint>(d_nativeHorzRes) << "\" ";
01270
01271 if (d_nativeVertRes != DefaultNativeVertRes)
01272 out_stream << "NativeVertRes=\"" << static_cast<uint>(d_nativeVertRes) << "\" ";
01273
01274 if (d_autoScale)
01275 out_stream << "AutoScaled=\"True\" ";
01276
01277 out_stream << ">" << std::endl;
01278
01279
01280 if (d_freetype)
01281 {
01282 size_t start = 0, idx = 0;
01283
01284 while(start < d_glyphset.length())
01285 {
01286
01287 while ((idx + 1 < d_glyphset.length()) && (d_glyphset[idx] + 1 == d_glyphset[idx + 1]))
01288 ++idx;
01289
01290 if (start == idx)
01291
01292 out_stream << "<Glyph Codepoint=\"" << d_glyphset[start] << "\" />" << std::endl;
01293 else
01294
01295 out_stream << "<GlyphRange StartCodepoint=\"" << d_glyphset[start] << "\" EndCodepoint=\"" << d_glyphset[idx] << "\" />" << std::endl;
01296
01297 start = ++idx;
01298 }
01299 }
01300
01301 else
01302 {
01303 for (CodepointMap::const_iterator iter = d_cp_map.begin(); iter != d_cp_map.end(); ++iter)
01304 {
01305 out_stream << "<Mapping Codepoint=\"" << (*iter).first << "\" Image=\"" << (*iter).second.d_image->getName() << "\" ";
01306
01307 if ((*iter).second.d_horz_advance_unscaled != -1)
01308 out_stream << "HorzAdvance=\"" << (*iter).second.d_horz_advance_unscaled << "\" ";
01309
01310 out_stream << "/>" << std::endl;
01311 }
01312 }
01313
01314
01315 out_stream << "</Font>" << std::endl;
01316 }
01317
01318
01319 }