1
// __________________________________________________________________________________________________
2
// GLGooey Graphical User Interface for OpenGL
3
// Copyright (c) 2004 Niel Waldren
5
// This software is provided 'as-is', without any express or implied warranty. In no event will
6
// the authors be held liable for any damages arising from the use of this software.
8
// Permission is granted to anyone to use this software for any purpose, including commercial
9
// applications, and to alter it and redistribute it freely, subject to the following restrictions:
11
// 1. The origin of this software must not be misrepresented; you must not claim that you
12
// wrote the original software. If you use this software in a product, an acknowledgment
13
// in the product documentation would be appreciated but is not required.
15
// 2. Altered source versions must be plainly marked as such, and must not be misrepresented
16
// as being the original software.
18
// 3. This notice may not be removed or altered from any source distribution.
20
// __________________________________________________________________________________________________
23
#include "mmgr/nommgr.h"
35
#include FT_FREETYPE_H
37
#include "SDL_opengl.h"
43
// *************************************************************************************************
44
// Data would be hidden inside an anonymous namespace, but msvc 6 can't handle it
47
static FT_Library ftlibrary_;
48
static bool FTinitialized=false;
50
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
51
//! Information on a cached glyph
54
size_t textureIndex_; //!< Index into the TypeFace's texture array
55
Vec2f topLeftUV_; //!< Texcoords for the top left corner of the glyph
56
Vec2f bottomRightUV_; //!< Texcoords for the bottom right corner of the glyph
57
Vec2size_t renderSize_; //!< The size of the glyph in pixels on the render target
58
Vec2f advance_; //!< The character advance for the cached glyph
59
Vec2f bitmapPosition_; //!< The offset from the pen to the top left corner of the bitmap
61
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
68
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
69
//! Information on a cache texture
72
typedef GLuint Handle; //!< typedef for a texture handle for an OpenGL texture
73
Handle handle_; //!< The OpenGL texture handle
74
Vec2size_t size_; //!< The size of the texture in texels
76
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
84
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
85
typedef std::vector<TextureInfo> Textures; //!< An array of textures
86
typedef std::map<FT_UInt, CacheEntry> CharacterCache; //!< The cache maps glyphs to cache entries
87
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
93
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
94
//! Implementation data for the TypeFace class
98
Data(size_t aPointSize, size_t aResolution) :
99
pointSize_(aPointSize), resolution_(aResolution) {}
101
size_t pointSize_; //!< The size of the type face in points
102
size_t resolution_; //!< The resolution of the type face in dpi
103
FT_Face face_; //!< A handle to the FreeType face object
104
CharacterCache characterCache_; //!< The glyph cache
105
Vec2i offset_; //!< The top left corner of the next glyph to be cached
106
Textures textures_; //!< The texture sizes and handles obtained from OpenGL
107
bool hasKerning_; //!< Set to true if the type face supports kerning
109
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
116
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
117
const size_t glyphPadding = 1; //!< Glyphs have padding around them to prevent filtering issues
118
const float OneOver64 = 0.015625f; //!< A frequently used constant
119
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
129
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
130
//! Returns the value of the next highest power of 2 above \c aValue
132
nextHighestPowerOf2(size_t aValue)
134
size_t v = aValue - 1;
135
for(int i = 16; i > 0; i >>= 1) v |= (v >> i);
138
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
145
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
146
//! Returns the maximum texture size permitted by the OpenGL implementation
151
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
152
if(maxSize > 512) maxSize = 512;
153
return static_cast<size_t>(maxSize);
155
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
161
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
162
//! returns the width to use for a cache texture
164
cacheTextureWidth(size_t aGlyphWidth, size_t numGlyphsToCache)
166
size_t width = nextHighestPowerOf2( ( (aGlyphWidth + glyphPadding) * numGlyphsToCache) + glyphPadding );
167
if(width > maximumTextureSize()) width = maximumTextureSize();
170
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
175
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
176
//! Returns the size to use for a cache texture
178
cacheTextureSize(const Vec2size_t& aGlyphSize, size_t numGlyphsToCache)
180
size_t textureWidth = cacheTextureWidth(aGlyphSize[0], numGlyphsToCache);
182
const size_t numGlyphsInRow = (textureWidth - (glyphPadding * 2)) / aGlyphSize[0];
183
const size_t requiredHeight = ((numGlyphsToCache / numGlyphsInRow) + 1) * aGlyphSize[1];
184
size_t textureHeight = nextHighestPowerOf2(requiredHeight);
185
if(textureHeight > maximumTextureSize()) textureHeight = maximumTextureSize();
187
return Vec2size_t(textureWidth, textureHeight);
189
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
197
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
198
//! Pushes the pixel storage client attributes and sets them to a standard packing mode
202
glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
204
// Enforce a standard packing mode
205
glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE );
206
glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE );
207
glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
208
glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
209
glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
211
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
213
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
219
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
220
//! Pops the pixel storage client attributes off the stack
222
restorePixelStorage()
226
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
234
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
235
//! Creates a texture for caching pre-rendered glyphs
237
createCacheTexture(const Vec2size_t& aGlyphSize, size_t numGlyphsToCache)
242
glGenTextures(1, &info.handle_);
244
glBindTexture(GL_TEXTURE_2D, info.handle_);
246
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
247
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
248
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
249
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
251
info.size_ = cacheTextureSize(aGlyphSize, numGlyphsToCache);
253
unsigned char* textureData = new unsigned char[info.size_[0]*info.size_[1]];
254
memset(textureData, 0, info.size_[0]*info.size_[1]);
256
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, info.size_[0], info.size_[1], 0, GL_ALPHA,
257
GL_UNSIGNED_BYTE, textureData);
259
restorePixelStorage();
261
delete[] textureData;
265
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
272
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
273
//! \brief Blits the glyph represented by the passed in bitmap to the texture described by
274
//! the passed in texture info.
276
blitGlyphToTexture(FT_Bitmap* aBitmap, const TextureInfo& aTextureInfo,
277
const Vec2i& anOffset, const Vec2size_t& aGlyphSize)
281
const int pitch = aBitmap->pitch;
282
unsigned char* data = new unsigned char[aGlyphSize[0]*aGlyphSize[1]];
284
for(size_t y = 0; y < aGlyphSize[1]; ++y)
286
memcpy(data + (y * aGlyphSize[0]), aBitmap->buffer + (y * pitch), aGlyphSize[0]);
289
glBindTexture(GL_TEXTURE_2D, aTextureInfo.handle_);
290
glTexSubImage2D(GL_TEXTURE_2D, 0, anOffset[0], anOffset[1],
291
aGlyphSize[0], aGlyphSize[1], GL_ALPHA, GL_UNSIGNED_BYTE, data);
295
restorePixelStorage();
297
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
305
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
306
//! Functor for destroying OpenGL textures
307
struct DestroyTexture
309
//! The function that does the destroying
311
operator() (const TextureInfo& info)
313
glDeleteTextures(1, &info.handle_);
316
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
320
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
321
TypeFace::TypeFace(const std::string& aFaceName, size_t aPointSize, size_t aResolution) :
322
data_(new Data(aPointSize, aResolution))
324
std::ifstream ifs(aFaceName.c_str(), std::ios_base::in);
327
std::cerr << "Error: cannot find TTF font file " << aFaceName << "." << std::endl;
331
if (FTinitialized==false)
333
assert(FT_Init_FreeType(&ftlibrary_) == 0);
334
FTinitialized = true;
337
assert(FT_New_Face(ftlibrary_, aFaceName.c_str(), 0, &data_->face_) == 0);
339
assert(FT_IS_SCALABLE(data_->face_));
340
assert(FT_IS_SFNT(data_->face_));
342
if( !data_->face_->charmap) FT_Set_Charmap(data_->face_, data_->face_->charmaps[0]);
344
assert(FT_Set_Char_Size(data_->face_, 0L, static_cast<FT_F26Dot6>(aPointSize << 6), aResolution, aResolution) == 0);
346
data_->hasKerning_ = (FT_HAS_KERNING(data_->face_) != 0);
348
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
354
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
355
TypeFace::~TypeFace()
358
FT_Done_Face(data_->face_);
361
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
368
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
370
TypeFace::pointSize() const
372
return data_->pointSize_;
374
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
380
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
382
TypeFace::setPointSize(size_t aPointSize)
384
if(data_->pointSize_ != aPointSize)
386
data_->pointSize_ = aPointSize;
387
const FT_F26Dot6 sz = static_cast<FT_F26Dot6>(aPointSize << 6);
388
assert(FT_Set_Char_Size(data_->face_, sz, sz, data_->resolution_, data_->resolution_) == 0);
392
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
399
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
401
TypeFace::resolution() const
403
return data_->resolution_;
405
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
413
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
415
TypeFace::setResolution(size_t aResolution)
417
if(data_->resolution_ != aResolution)
419
data_->resolution_ = aResolution;
423
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
430
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
431
float TypeFace::ascent() const
433
return float(data_->face_->size->metrics.y_ppem) - descent();
435
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
444
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
445
float TypeFace::descent() const
447
return static_cast<float>(-data_->face_->size->metrics.descender) * OneOver64;
449
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
456
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
457
float TypeFace::lineHeight() const
459
return (ascent() + descent());
461
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
470
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
472
TypeFace::flushCache()
474
data_->characterCache_.clear();
475
std::for_each(data_->textures_.begin(), data_->textures_.end(), DestroyTexture());
476
data_->textures_.clear();
478
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
485
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
487
TypeFace::addNewTexture(const Vec2size_t& aGlyphSize)
489
const size_t numUncachedGlyphs = data_->face_->num_glyphs - data_->characterCache_.size();
490
data_->textures_.push_back(createCacheTexture(aGlyphSize, numUncachedGlyphs));
491
data_->offset_.set(glyphPadding, glyphPadding);
493
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
502
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
504
TypeFace::render(const std::wstring& aString, const Vec2f& aPosition, bool upsideDown)
506
glPushAttrib(GL_ALL_ATTRIB_BITS);
507
glEnable(GL_TEXTURE_2D);
510
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
513
glTranslatef(aPosition[0], aPosition[1], 0.0f);
516
glScalef(1.f, -1.f, 1.f);
517
glTranslatef(0.f, lineHeight(), 0.f);
520
renderGlyphs(aString);
526
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
533
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
535
TypeFace::width(const std::wstring& aString)
537
std::wstring::const_iterator it = aString.begin();
540
while(it != aString.end())
542
size_t rightChar = FT_Get_Char_Index(data_->face_, *it);
543
ret += kerning(leftChar, rightChar)[0];
544
ret += cachedGlyph(rightChar).advance_[0];
545
leftChar = rightChar;
550
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
556
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
557
size_t TypeFace::hitCharacterIndex(const std::wstring& aString, float anOffset)
561
size_t characterIndex = 0;
564
std::wstring::const_iterator it = aString.begin();
567
while(it != aString.end())
569
float newOffset = oldOffset;
570
size_t rightChar = FT_Get_Char_Index(data_->face_, *it);
571
newOffset += kerning(leftChar, rightChar)[0];
572
newOffset += cachedGlyph(rightChar).advance_[0];
574
if( (newOffset >= anOffset) && (oldOffset <= anOffset) )
580
leftChar = rightChar;
581
oldOffset = newOffset;
587
if(!found) characterIndex = std::wstring::npos;
589
return characterIndex;
591
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
597
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
599
TypeFace::addCacheEntry(FT_GlyphRec_* aGlyph, FT_BitmapGlyphRec_* aBitmapGlyph, size_t aGlyphIndex, const Vec2size_t& aGlyphSize)
601
const TextureInfo& textureInfo = *(data_->textures_.rbegin());
603
const Vec2i bottomRight = data_->offset_ + Vec2i(aGlyphSize[0], aGlyphSize[1]);
605
const float widthF = static_cast<float>(textureInfo.size_[0]);
606
const float heightF = static_cast<float>(textureInfo.size_[1]);
609
entry.topLeftUV_[0]=static_cast<float>(data_->offset_[0]) / widthF;
610
entry.topLeftUV_[1]=static_cast<float>(data_->offset_[1]) / heightF;
611
entry.bottomRightUV_[0]=static_cast<float>(bottomRight[0]) / widthF;
612
entry.bottomRightUV_[1]=static_cast<float>(bottomRight[1]) / heightF;
613
entry.textureIndex_ = data_->textures_.size() - 1;
614
entry.renderSize_ = aGlyphSize;
615
entry.advance_ = Vec2f(float(aGlyph->advance.x >> 16), float(aGlyph->advance.y >> 16));
616
entry.bitmapPosition_ = Vec2f(float(aBitmapGlyph->left), float(-aBitmapGlyph->top));
618
data_->characterCache_[aGlyphIndex] = entry;
620
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
627
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
629
TypeFace::maximumGlyphSize() const
631
FT_BBox& bounds = data_->face_->bbox;
632
float maxGlyphWidthF = static_cast<float>(bounds.xMax - bounds.xMin);
633
maxGlyphWidthF *= ( (float)data_->face_->size->metrics.x_ppem / (float)data_->face_->units_per_EM);
635
float maxGlyphHeightF = static_cast<float>(bounds.yMax - bounds.yMin);
636
maxGlyphHeightF *= ( (float)data_->face_->size->metrics.y_ppem / (float)data_->face_->units_per_EM);
638
return Vec2size_t(static_cast<size_t>(maxGlyphWidthF), static_cast<size_t>(maxGlyphHeightF));
640
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
647
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
649
TypeFace::ensureTextureIsAvailable()
651
const Vec2size_t maxGlyphSize = maximumGlyphSize();
653
if(data_->textures_.size() == 0)
655
addNewTexture(maxGlyphSize);
659
const TextureInfo& textureInfo = *(data_->textures_.rbegin());
660
if(data_->offset_[0] > int(textureInfo.size_[0]) - int(maxGlyphSize[0]) - int(glyphPadding))
662
data_->offset_.set(glyphPadding, data_->offset_[1] + maxGlyphSize[1]);
664
if(data_->offset_[1] > int(textureInfo.size_[1]) - int(maxGlyphSize[1]) - int(glyphPadding))
666
addNewTexture(maxGlyphSize);
671
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
678
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
680
TypeFace::cacheGlyph(size_t aGlyphIndex)
682
ensureTextureIsAvailable();
684
const FT_Error loadError = FT_Load_Glyph(data_->face_, aGlyphIndex, FT_LOAD_NO_HINTING);
685
assert(loadError == 0);
689
const FT_Error getError = FT_Get_Glyph( data_->face_->glyph, &glyph);
692
const FT_Error bitmapError = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1);
693
if( (bitmapError == 0) && (glyph->format == FT_GLYPH_FORMAT_BITMAP) )
695
FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
696
FT_Bitmap* bitmap = &bitmapGlyph->bitmap;
698
const Vec2size_t glyphSize(bitmap->width, bitmap->rows);
700
if(glyphSize[0]*glyphSize[1] > 0)
701
blitGlyphToTexture(bitmap, *(data_->textures_.rbegin()), data_->offset_, glyphSize);
703
addCacheEntry(glyph, bitmapGlyph, aGlyphIndex, glyphSize);
704
data_->offset_[0]=data_->offset_[0] + glyphSize[0] + glyphPadding;
707
FT_Done_Glyph(glyph);
710
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
718
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
720
TypeFace::cachedGlyph(size_t aGlyphIndex)
722
CharacterCache::iterator cacheIterator = data_->characterCache_.find(aGlyphIndex);
723
if(cacheIterator == data_->characterCache_.end())
725
cacheGlyph(aGlyphIndex);
726
cacheIterator = data_->characterCache_.find(aGlyphIndex);
727
assert(cacheIterator != data_->characterCache_.end());
729
return cacheIterator->second;
731
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
741
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
743
TypeFace::renderGlyph(size_t aGlyphIndex, const Vec2f& aPosition)
745
CacheEntry& entry = cachedGlyph(aGlyphIndex);
749
const Vec2f position = aPosition + entry.bitmapPosition_;
751
const Vec2f topLeftUV = entry.topLeftUV_;
752
const Vec2f bottomRightUV = entry.bottomRightUV_;
753
const float glyphWidth = static_cast<float>(entry.renderSize_[0]);
754
const float glyphHeight = static_cast<float>(entry.renderSize_[1]);
758
glTexCoord2f( topLeftUV[0], topLeftUV[1] );
759
glVertex2f( position[0], position[1] );
761
glTexCoord2f( bottomRightUV[0], topLeftUV[1] );
762
glVertex2f( position[0] + glyphWidth, position[1] );
764
glTexCoord2f( bottomRightUV[0], bottomRightUV[1] );
765
glVertex2f( position[0] + glyphWidth, position[1] + glyphHeight );
767
glTexCoord2f( topLeftUV[0], bottomRightUV[1] );
768
glVertex2f( position[0], position[1] + glyphHeight );
772
return entry.advance_;
774
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
780
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
782
TypeFace::kerning(size_t leftGlyphIndex, size_t rightGlyphIndex) const
785
if(data_->hasKerning_ && (leftGlyphIndex > 0) && (rightGlyphIndex > 0))
787
FT_Vector kerningVector;
788
FT_Error ftError = FT_Get_Kerning(data_->face_, leftGlyphIndex, rightGlyphIndex, FT_KERNING_DEFAULT, &kerningVector);
791
ret = Vec2f(static_cast<float>(kerningVector.x),
792
static_cast<float>(kerningVector.y)) * OneOver64;
797
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
805
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
807
TypeFace::bindTexture(const CacheEntry& aCacheEntry) const
809
assert(aCacheEntry.textureIndex_ < data_->textures_.size());
810
const TextureInfo& info = data_->textures_[aCacheEntry.textureIndex_];
812
GLint currentTextureID = -1;
813
glGetIntegerv(GL_TEXTURE_2D_BINDING_EXT, ¤tTextureID);
814
if(static_cast<GLuint>(currentTextureID) != info.handle_)
816
glBindTexture(GL_TEXTURE_2D, info.handle_);
819
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
827
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
829
TypeFace::renderGlyphs(const std::wstring& aString)
831
Vec2f pos(0.0f, 0.0f);
833
std::wstring::const_iterator it = aString.begin();
834
while(it != aString.end())
836
size_t rightChar = FT_Get_Char_Index(data_->face_, *it);
837
pos += kerning(leftChar, rightChar);
838
pos += renderGlyph(rightChar, pos);
839
leftChar = rightChar;