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