00001 #ifndef _FONT_H_
00002 #define _FONT_H_
00003
00004 #include <limits>
00005 #include <string>
00006 #include <stdexcept>
00007 #include <map>
00008 #include <cmath>
00009
00011 namespace glttf {
00012
00014
00028 class Font
00029 {
00030 public:
00032 static const unsigned long DEFAULT_FACE_INDEX = 0;
00033
00035 typedef unsigned char FontStyle;
00037 static const FontStyle PLAIN = 0x0;
00039 static const FontStyle BOLD = 0x1;
00041 static const FontStyle ITALIC = 0x2;
00042
00044 typedef unsigned char Flags;
00046 static const Flags FLIP_Y_AXIS = 0x1;
00048 static const Flags SCALE_TO_1EM = 0x2;
00050 static const Flags TOP_LEFT_ORIGIN = 0x4;
00051
00053 static const float BOLD_WEIGHT;
00055 static const float ITALIC_SHEAR;
00056
00058
00078 Font(const std::string &filename, unsigned int size, FontStyle style, unsigned long faceIndex = DEFAULT_FACE_INDEX);
00079
00081
00088 virtual ~Font();
00089
00091
00106 void setPixelSize(unsigned int width, unsigned int height = 0);
00107
00109
00127 void setCharSize(float width, float height, unsigned int hres = 0, unsigned int vres = 0);
00128
00130
00140 void setTransformation(float weight, float shear);
00141
00143
00151 void setStyle(FontStyle style);
00152
00154
00171 Glyph &getGlyph(unsigned long ch, bool cache);
00172
00174
00187 void drawCharacter(unsigned long ch, bool cache = true);
00188
00190
00205 template<typename Iterator>
00206 void drawString(Iterator begin, Iterator end, bool cache = true);
00207
00209
00229 template<typename Iterator>
00230 void getBoundingBox(Iterator begin, Iterator end, float &minX, float &minY, float &maxX, float &maxY, bool cache = true);
00231
00233
00241 void drawString(std::string const &str, bool cache = true);
00242
00244
00257 void getBoundingBox(std::string const &str, float &minX, float &minY, float &maxX, float &maxY, bool cache = true);
00258
00259 #ifdef HAVE_WSTRING
00261
00269 void drawString(std::wstring const &str, bool cache = true);
00270
00272
00285 void getBoundingBox(std::wstring const &str, float &minX, float &minY, float &maxX, float &maxY, bool cache = true);
00286 #endif
00287
00289
00296 void buildCache(unsigned long from = 0, unsigned long to = 127);
00297
00299
00310 virtual void setupState();
00311
00313
00324 virtual void cleanupState();
00325
00327
00335 void setScaleTo1EM(bool enable);
00336
00338
00341 bool getScaleTo1EM() const;
00342
00344
00350 void setFlipYAxis(bool enable);
00351
00353
00356 bool getFlipYAxis() const;
00357
00359
00364 void setTopLeftOrigin(bool enable);
00365
00367
00370 bool getTopLeftOrigin() const;
00371
00373
00376 Flags getFlags() const;
00377
00379
00382 void setFlags(Flags f);
00383
00385
00388 float getTextHeight() const;
00389
00391
00394 float getUnitsPerEM() const;
00395
00397
00400 float getAscender() const;
00401
00403
00406 float getDescender() const;
00407
00409
00415 float getMaxAdvanceX() const;
00416
00418
00421 float getMaxAdvanceY() const;
00422
00424
00427 float getWeight() const;
00428
00430
00433 float getShear() const;
00434
00436
00439 unsigned int getTabSize() const;
00440
00442
00445 void setTabSize(unsigned int size);
00446
00448
00454 void setTabWidth(float width);
00455
00457
00461 float getTabWidth() const;
00462
00464
00471 float getTabWidth(bool cache = true);
00472
00473 protected:
00474 unsigned int getCharIndex(unsigned long charcode) const;
00475 FT_GlyphSlot getFTGlyph(unsigned int index) const;
00476
00478
00485 void deleteCache();
00486
00488
00499 virtual Glyph *makeGlyph(FT_GlyphSlot glyph) = 0;
00500
00501 private:
00502 Font(const Font& font);
00503 Font &operator=(const Font &font);
00504
00505 unsigned int stateSet;
00506 Flags flags;
00507 unsigned int tabSize;
00508 float tabWidth;
00509
00510 typedef std::map<unsigned long, Glyph*> GlyphMap;
00511 GlyphMap glyphs;
00512
00513 void loadCharacter(unsigned long ch);
00514
00515 void initLibrary();
00516 void deinitLibrary();
00517 FT_Face face;
00518
00519 bool kerning;
00520
00521 FontStyle style;
00522 float weight, shear;
00523
00524 float textHeight;
00525 float unitsPerEM;
00526 float ascender, descender;
00527 float maxAdvanceX, maxAdvanceY;
00528
00529 static FT_Library library;
00530 static int instances;
00531
00532 void calculateTabWidth(bool cache);
00533 };
00534
00535 template<typename Iterator>
00536 void Font::drawString(Iterator begin, Iterator end, bool cache)
00537 {
00538 setupState();
00539
00540 glPushMatrix();
00541
00542 if(flags & FLIP_Y_AXIS) glScalef(1.0f, -1.0f, 1.0f);
00543 if(flags & SCALE_TO_1EM)
00544 {
00545 float scale = 1.0 / unitsPerEM;
00546 glScalef(scale, scale, scale);
00547 }
00548 if(flags & TOP_LEFT_ORIGIN) glTranslatef(0.0f, -ascender, 0.0f);
00549
00550 glPushMatrix();
00551
00552 float x0 = 0.0f;
00553 unsigned int prev = 0;
00554 for(Iterator i(begin); i != end; ++i)
00555 {
00556 unsigned long ch = (*i < 0)?(0):(*i);
00557
00558 if(kerning)
00559 {
00560 unsigned int index = getCharIndex(ch);
00561
00562 if(prev && index)
00563 {
00564 FT_Vector delta;
00565 if(FT_Get_Kerning(face, prev, index, FT_KERNING_DEFAULT, &delta))
00566 {
00567 glPopMatrix();
00568 glPopMatrix();
00569 cleanupState();
00570 throw std::runtime_error("Can't get glyph kerning");
00571 }
00572
00573 glTranslatef(weight * delta.x / 64.0f, 0.0f, 0.0f);
00574 }
00575
00576 prev = index;
00577 }
00578
00579
00580 if(ch == '\n')
00581 {
00582 x0 = 0.0f;
00583 glPopMatrix();
00584 glTranslatef(0.0f, -textHeight, 0.0f);
00585 glPushMatrix();
00586 continue;
00587 } else if(ch == '\r')
00588 {
00589 continue;
00590 } else if(ch == '\t')
00591 {
00592 ch = ' ';
00593 prev = getCharIndex(ch);
00594
00595 if(tabWidth < 0.0)
00596 {
00597 try
00598 {
00599 calculateTabWidth(cache);
00600 } catch(...)
00601 {
00602 glPopMatrix();
00603 glPopMatrix();
00604 cleanupState();
00605 throw;
00606 }
00607 }
00608
00609 float tx = std::floor((x0 + tabWidth) / tabWidth) * tabWidth;
00610 glTranslatef(tx - x0, 0.0f ,0.0f);
00611 x0 = tx;
00612
00613 continue;
00614 }
00615
00616 try
00617 {
00618 const Glyph &glyph = getGlyph(ch, cache);
00619 glyph.draw();
00620 glTranslatef(weight * glyph.getAdvanceX(), 0.0f, 0.0f);
00621 x0 += glyph.getAdvanceX() * weight;
00622 } catch(...)
00623 {
00624 glPopMatrix();
00625 glPopMatrix();
00626 cleanupState();
00627 throw;
00628 }
00629 }
00630
00631 glPopMatrix();
00632 glPopMatrix();
00633 cleanupState();
00634 }
00635
00636 template<typename Iterator>
00637 void Font::getBoundingBox(Iterator begin, Iterator end, float &minX, float &minY, float &maxX, float &maxY, bool cache)
00638 {
00639 float x0 = 0.0;
00640 float y0 = 0.0;
00641
00642 const float MAX = std::numeric_limits<float>::max();
00643 const float MIN = std::numeric_limits<float>::min();
00644 minX = MAX;
00645 maxX = MIN;
00646 minY = MAX;
00647 maxY = MIN;
00648
00649 unsigned int prev = 0;
00650 for(Iterator i(begin); i != end; ++i)
00651 {
00652 unsigned long ch = (*i < 0)?(0):(*i);
00653
00654 unsigned int index = getCharIndex(ch);
00655 if(kerning && index)
00656 {
00657 if(prev)
00658 {
00659 FT_Vector delta;
00660 if(FT_Get_Kerning(face, prev, index, FT_KERNING_DEFAULT, &delta))
00661 {
00662 throw std::runtime_error("Can't get glyph kerning");
00663 }
00664 x0 += weight * delta.x / 64.0f;
00665 }
00666 }
00667 prev = index;
00668
00669
00670 if(ch == '\n')
00671 {
00672 x0 = 0.0f;
00673 y0 -= textHeight;
00674 continue;
00675 } else if(ch == '\r')
00676 {
00677 continue;
00678 } else if(ch == '\t')
00679 {
00680 ch = ' ';
00681 prev = index = getCharIndex(ch);
00682
00683 if(tabWidth < 0.0f) calculateTabWidth(cache);
00684
00685 x0 = std::floor((x0 + tabWidth) / tabWidth) * tabWidth;
00686
00687 continue;
00688 }
00689
00690 float x1, y1, x2, y2;
00691
00692 const Glyph &glyph = getGlyph(ch, cache);
00693
00694 x1 = x0 + glyph.getMinX();
00695 y1 = y0 + glyph.getMinY();
00696 x2 = x0 + glyph.getMaxX();
00697 y2 = y0 + glyph.getMaxY();
00698
00699 x0 += glyph.getAdvanceX() * weight;
00700
00701 if(x1 < minX) minX = x1;
00702 if(y1 < minY) minY = y1;
00703 if(x2 > maxX) maxX = x2;
00704 if(y2 > maxY) maxY = y2;
00705 }
00706
00707 if(flags & FLIP_Y_AXIS)
00708 {
00709 minY = -minY;
00710 maxY = -maxY;
00711 }
00712
00713 float scale = 1.0;
00714 if(flags & SCALE_TO_1EM)
00715 {
00716 scale = 1.0 / unitsPerEM;
00717 maxX *= scale;
00718 minX *= scale;
00719 maxY *= scale;
00720 minY *= scale;
00721 }
00722
00723 if(flags & FLIP_Y_AXIS) scale = -scale;
00724
00725 if(flags & TOP_LEFT_ORIGIN)
00726 {
00727 minY -= ascender * scale;
00728 maxY -= ascender * scale;
00729 }
00730 }
00731
00732
00734
00738 template <class T>
00739 class BasicFont : public Font
00740 {
00741 public:
00743 typedef T GlyphType;
00744
00746 typedef typename T::Parameter Parameter;
00747
00749
00757 BasicFont(const std::string &filename, unsigned int size = 32, Font::FontStyle style = Font::PLAIN, unsigned long faceIndex = Font::DEFAULT_FACE_INDEX)
00758 : Font(filename, size, style, faceIndex), stateSet(0), parameter(GlyphType::DEFAULT_PARAMETER)
00759 {
00760 }
00761
00763 ~BasicFont() {}
00764
00766
00770 void setupState()
00771 {
00772 if(stateSet)
00773 {
00774 ++stateSet;
00775 return;
00776 }
00777 ++stateSet;
00778
00779 Font::setupState();
00780 GlyphType::setupState();
00781 }
00782
00784
00789 void cleanupState()
00790 {
00791 if(!stateSet) return;
00792 --stateSet;
00793 if(stateSet) return;
00794
00795 GlyphType::cleanupState();
00796 Font::cleanupState();
00797 }
00798
00800
00805 void setParameter(const Parameter ¶m)
00806 {
00807 if(stateSet) throw std::logic_error("Can't set font parameters when in rendering state");
00808 deleteCache();
00809 parameter = param;
00810 }
00811
00813
00816 const Parameter &getParameter() const
00817 {
00818 return parameter;
00819 }
00820 protected:
00822
00830 Glyph *makeGlyph(FT_GlyphSlot glyph)
00831 {
00832 return dynamic_cast<Glyph*>(new GlyphType(glyph, parameter));
00833 }
00834 private:
00835 BasicFont(const BasicFont<GlyphType> &font);
00836 BasicFont& operator=(const BasicFont<GlyphType> &font);
00837 int stateSet;
00838
00839 Parameter parameter;
00840 };
00841
00842 }
00843
00844 #endif
00845