aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llrender/llfont.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/llrender/llfont.cpp187
1 files changed, 64 insertions, 123 deletions
diff --git a/linden/indra/llrender/llfont.cpp b/linden/indra/llrender/llfont.cpp
index d7310bd..9245803 100644
--- a/linden/indra/llrender/llfont.cpp
+++ b/linden/indra/llrender/llfont.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception 18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -52,6 +53,8 @@
52#include "llmath.h" // Linden math 53#include "llmath.h" // Linden math
53#include "llstring.h" 54#include "llstring.h"
54//#include "imdebug.h" 55//#include "imdebug.h"
56#include "llfontbitmapcache.h"
57#include "llgl.h"
55 58
56FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL; 59FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL;
57 60
@@ -124,30 +127,28 @@ void LLFontList::addAtEnd(LLFont *font)
124 this->push_back(font); 127 this->push_back(font);
125} 128}
126 129
127LLFont::LLFont(LLImageRaw *imagep) 130LLFont::LLFont()
128 : mRawImagep(imagep)
129{ 131{
132 mFontBitmapCachep = new LLFontBitmapCache;
133
130 mValid = FALSE; 134 mValid = FALSE;
131 mAscender = 0.f; 135 mAscender = 0.f;
132 mDescender = 0.f; 136 mDescender = 0.f;
133 mLineHeight = 0.f; 137 mLineHeight = 0.f;
134 mBitmapWidth = 0; 138
135 mBitmapHeight = 0;
136 mCurrentOffsetX = 1;
137 mCurrentOffsetY = 1;
138 mMaxCharWidth = 0;
139 mMaxCharHeight = 0;
140 mNumComponents = 0;
141 mFallbackFontp = NULL; 139 mFallbackFontp = NULL;
142 mIsFallback = FALSE; 140 mIsFallback = FALSE;
143 mFTFace = NULL; 141 mFTFace = NULL;
142
143 mRenderGlyphCount = 0;
144 mAddGlyphCount = 0;
145
146 mPointSize = 0;
144} 147}
145 148
146 149
147LLFont::~LLFont() 150LLFont::~LLFont()
148{ 151{
149 mRawImagep = NULL; // dereferences or deletes image
150
151 // Clean up freetype libs. 152 // Clean up freetype libs.
152 if (mFTFace) 153 if (mFTFace)
153 FT_Done_Face(mFTFace); 154 FT_Done_Face(mFTFace);
@@ -155,11 +156,8 @@ LLFont::~LLFont()
155 156
156 // Delete glyph info 157 // Delete glyph info
157 std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer()); 158 std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer());
158}
159 159
160void LLFont::setRawImage(LLImageRaw *imagep) 160 // mFontBitmapCachep will be cleaned up by LLPointer destructor.
161{
162 mRawImagep = imagep; // will delete old raw image if we have one and created it
163} 161}
164 162
165// virtual 163// virtual
@@ -203,7 +201,6 @@ BOOL LLFont::loadFace(const std::string& filename, const F32 point_size, const F
203 } 201 }
204 202
205 mIsFallback = is_fallback; 203 mIsFallback = is_fallback;
206 mNumComponents = components;
207 F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi 204 F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi
208 205
209 error = FT_Set_Char_Size(mFTFace, /* handle to face object */ 206 error = FT_Set_Char_Size(mFTFace, /* handle to face object */
@@ -233,8 +230,10 @@ BOOL LLFont::loadFace(const std::string& filename, const F32 point_size, const F
233 mDescender = -mFTFace->descender * pixels_per_unit; 230 mDescender = -mFTFace->descender * pixels_per_unit;
234 mLineHeight = mFTFace->height * pixels_per_unit; 231 mLineHeight = mFTFace->height * pixels_per_unit;
235 232
236 mMaxCharWidth = llround(0.5f + (x_max - x_min)); 233 S32 max_char_width = llround(0.5f + (x_max - x_min));
237 mMaxCharHeight = llround(0.5f + (y_max - y_min)); 234 S32 max_char_height = llround(0.5f + (y_max - y_min));
235
236 mFontBitmapCachep->init(components, max_char_width, max_char_height);
238 237
239 if (!mFTFace->charmap) 238 if (!mFTFace->charmap)
240 { 239 {
@@ -242,62 +241,20 @@ BOOL LLFont::loadFace(const std::string& filename, const F32 point_size, const F
242 FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]); 241 FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]);
243 } 242 }
244 243
245 if (mRawImagep.isNull() && !mIsFallback)
246 {
247 mRawImagep = new LLImageRaw();
248 }
249
250 if (!mIsFallback) 244 if (!mIsFallback)
251 { 245 {
252 // Place text into bitmap, and generate all necessary positions/
253 // offsets for the individual characters.
254
255 // calc width and height for mRawImagep (holds all characters)
256 // Guess for approximately 20*20 characters
257 S32 image_width = mMaxCharWidth * 20;
258 S32 pow_iw = 2;
259 while (pow_iw < image_width)
260 {
261 pow_iw *= 2;
262 }
263 image_width = pow_iw;
264 image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever.
265 S32 image_height = image_width;
266
267 //llinfos << "Guessing texture size of " << image_width << " pixels square" << llendl;
268
269 mRawImagep->resize(image_width, image_height, components);
270
271 mBitmapWidth = image_width;
272 mBitmapHeight = image_height;
273
274 switch (components)
275 {
276 case 1:
277 mRawImagep->clear();
278 break;
279 case 2:
280 mRawImagep->clear(255, 0);
281 break;
282 }
283
284 mCurrentOffsetX = 1;
285 mCurrentOffsetY = 1;
286
287 // Add the default glyph 246 // Add the default glyph
288 addGlyph(0, 0); 247 addGlyph(0, 0);
289 } 248 }
290 249
291 mName = filename; 250 mName = filename;
251 mPointSize = point_size;
292 252
293 return TRUE; 253 return TRUE;
294} 254}
295 255
296 256void LLFont::resetBitmapCache()
297void LLFont::resetBitmap()
298{ 257{
299 llinfos << "Rebuilding bitmap for glyph" << llendl;
300
301 // Iterate through glyphs and clear the mIsRendered flag 258 // Iterate through glyphs and clear the mIsRendered flag
302 for (char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.begin(); 259 for (char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.begin();
303 iter != mCharGlyphInfoMap.end(); ++iter) 260 iter != mCharGlyphInfoMap.end(); ++iter)
@@ -307,9 +264,7 @@ void LLFont::resetBitmap()
307 //not just flushing the bitmap 264 //not just flushing the bitmap
308 iter->second->mMetricsValid = FALSE; 265 iter->second->mMetricsValid = FALSE;
309 } 266 }
310 mRawImagep->clear(255, 0); 267 mFontBitmapCachep->reset();
311 mCurrentOffsetX = 1;
312 mCurrentOffsetY = 1;
313 268
314 // Add the empty glyph`5 269 // Add the empty glyph`5
315 addGlyph(0, 0); 270 addGlyph(0, 0);
@@ -340,7 +295,7 @@ BOOL LLFont::hasGlyph(const llwchar wch) const
340 } 295 }
341} 296}
342 297
343BOOL LLFont::addChar(const llwchar wch) 298BOOL LLFont::addChar(const llwchar wch) const
344{ 299{
345 if (mFTFace == NULL) 300 if (mFTFace == NULL)
346 return FALSE; 301 return FALSE;
@@ -375,7 +330,6 @@ BOOL LLFont::addChar(const llwchar wch)
375 if (iter == mCharGlyphInfoMap.end() || !(iter->second->mIsRendered)) 330 if (iter == mCharGlyphInfoMap.end() || !(iter->second->mIsRendered))
376 { 331 {
377 BOOL result = addGlyph(wch, glyph_index); 332 BOOL result = addGlyph(wch, glyph_index);
378 //imdebug("luma b=8 w=%d h=%d t=%s %p", mRawImagep->getWidth(), mRawImagep->getHeight(), mName.c_str(), mRawImagep->getData());
379 return result; 333 return result;
380 } 334 }
381 return FALSE; 335 return FALSE;
@@ -395,7 +349,7 @@ void LLFont::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
395 } 349 }
396} 350}
397 351
398BOOL LLFont::addGlyphFromFont(LLFont *fontp, const llwchar wch, const U32 glyph_index) 352BOOL LLFont::addGlyphFromFont(const LLFont *fontp, const llwchar wch, const U32 glyph_index) const
399{ 353{
400 if (mFTFace == NULL) 354 if (mFTFace == NULL)
401 return FALSE; 355 return FALSE;
@@ -405,35 +359,15 @@ BOOL LLFont::addGlyphFromFont(LLFont *fontp, const llwchar wch, const U32 glyph_
405 S32 width = fontp->mFTFace->glyph->bitmap.width; 359 S32 width = fontp->mFTFace->glyph->bitmap.width;
406 S32 height = fontp->mFTFace->glyph->bitmap.rows; 360 S32 height = fontp->mFTFace->glyph->bitmap.rows;
407 361
408 if ((mCurrentOffsetX + width + 1) > mRawImagep->getWidth()) 362 S32 pos_x, pos_y;
409 { 363 S32 bitmap_num;
410 if ((mCurrentOffsetY + 2*mMaxCharHeight + 2) > mBitmapHeight) 364 mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_num);
411 { 365 mAddGlyphCount++;
412 // We're out of space in this texture - clear it an all of the glyphs
413 // and start over again. Easier than LRU and should work just as well
414 // (just slightly slower on the rebuild). As long as the texture has
415 // enough room to hold all glyphs needed for a particular frame this
416 // shouldn't be too slow.
417
418 resetBitmap();
419
420 // Need to rerender the glyph, as it's been overwritten by the default glyph.
421 fontp->renderGlyph(glyph_index);
422 width = fontp->mFTFace->glyph->bitmap.width;
423 height = fontp->mFTFace->glyph->bitmap.rows;
424
425 // We should have a reasonable offset for x and y, no need to check that it's in range
426 }
427 else
428 {
429 mCurrentOffsetX = 1;
430 mCurrentOffsetY += mMaxCharHeight + 1;
431 }
432 }
433 366
434 LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index); 367 LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index);
435 gi->mXBitmapOffset = mCurrentOffsetX; 368 gi->mXBitmapOffset = pos_x;
436 gi->mYBitmapOffset = mCurrentOffsetY; 369 gi->mYBitmapOffset = pos_y;
370 gi->mBitmapNum = bitmap_num;
437 gi->mWidth = width; 371 gi->mWidth = width;
438 gi->mHeight = height; 372 gi->mHeight = height;
439 gi->mXBearing = fontp->mFTFace->glyph->bitmap_left; 373 gi->mXBearing = fontp->mFTFace->glyph->bitmap_left;
@@ -482,24 +416,25 @@ BOOL LLFont::addGlyphFromFont(LLFont *fontp, const llwchar wch, const U32 glyph_
482 buffer_row_stride = width; 416 buffer_row_stride = width;
483 } 417 }
484 418
485 switch (mNumComponents) 419 switch (mFontBitmapCachep->getNumComponents())
486 { 420 {
487 case 1: 421 case 1:
488 mRawImagep->setSubImage(mCurrentOffsetX, 422 mFontBitmapCachep->getImageRaw(bitmap_num)->setSubImage(pos_x,
489 mCurrentOffsetY, 423 pos_y,
490 width, 424 width,
491 height, 425 height,
492 buffer_data, 426 buffer_data,
493 buffer_row_stride, 427 buffer_row_stride,
494 TRUE); 428 TRUE);
495 break; 429 break;
496 case 2: 430 case 2:
497 setSubImageLuminanceAlpha(mCurrentOffsetX, 431 setSubImageLuminanceAlpha(pos_x,
498 mCurrentOffsetY, 432 pos_y,
499 width, 433 bitmap_num,
500 height, 434 width,
501 buffer_data, 435 height,
502 buffer_row_stride); 436 buffer_data,
437 buffer_row_stride);
503 break; 438 break;
504 default: 439 default:
505 break; 440 break;
@@ -512,11 +447,10 @@ BOOL LLFont::addGlyphFromFont(LLFont *fontp, const llwchar wch, const U32 glyph_
512 // omit it from the font-image. 447 // omit it from the font-image.
513 } 448 }
514 449
515 mCurrentOffsetX += width + 1;
516 return TRUE; 450 return TRUE;
517} 451}
518 452
519BOOL LLFont::addGlyph(const llwchar wch, const U32 glyph_index) 453BOOL LLFont::addGlyph(const llwchar wch, const U32 glyph_index) const
520{ 454{
521 return addGlyphFromFont(this, wch, glyph_index); 455 return addGlyphFromFont(this, wch, glyph_index);
522} 456}
@@ -557,7 +491,7 @@ F32 LLFont::getXAdvance(const llwchar wch) const
557 if (glyph_index) 491 if (glyph_index)
558 { 492 {
559 // This font has this glyph 493 // This font has this glyph
560 (const_cast<LLFont *>(fontp))->renderGlyph(glyph_index); 494 fontp->renderGlyph(glyph_index);
561 495
562 // Create the entry if it's not there 496 // Create the entry if it's not there
563 char_glyph_info_map_t::iterator iter2 = mCharGlyphInfoMap.find(wch); 497 char_glyph_info_map_t::iterator iter2 = mCharGlyphInfoMap.find(wch);
@@ -590,11 +524,11 @@ F32 LLFont::getXAdvance(const llwchar wch) const
590 } 524 }
591 525
592 // Last ditch fallback - no glyphs defined at all. 526 // Last ditch fallback - no glyphs defined at all.
593 return (F32)mMaxCharWidth; 527 return (F32)mFontBitmapCachep->getMaxCharWidth();
594} 528}
595 529
596 530
597void LLFont::renderGlyph(const U32 glyph_index) 531void LLFont::renderGlyph(const U32 glyph_index) const
598{ 532{
599 if (mFTFace == NULL) 533 if (mFTFace == NULL)
600 return; 534 return;
@@ -603,6 +537,9 @@ void LLFont::renderGlyph(const U32 glyph_index)
603 llassert(!error); 537 llassert(!error);
604 538
605 error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode); 539 error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode);
540
541 mRenderGlyphCount++;
542
606 llassert(!error); 543 llassert(!error);
607} 544}
608 545
@@ -627,16 +564,20 @@ F32 LLFont::getXKerning(const llwchar char_left, const llwchar char_right) const
627} 564}
628 565
629void LLFont::setSubImageLuminanceAlpha(const U32 x, 566void LLFont::setSubImageLuminanceAlpha(const U32 x,
630 const U32 y, 567 const U32 y,
631 const U32 width, 568 const U32 bitmap_num,
632 const U32 height, 569 const U32 width,
633 const U8 *data, 570 const U32 height,
634 S32 stride) 571 const U8 *data,
572 S32 stride) const
635{ 573{
574 LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num);
575
636 llassert(!mIsFallback); 576 llassert(!mIsFallback);
637 llassert(mRawImagep->getComponents() == 2); 577 llassert(image_raw && (image_raw->getComponents() == 2));
638 578
639 U8 *target = mRawImagep->getData(); 579
580 U8 *target = image_raw->getData();
640 581
641 if (!data) 582 if (!data)
642 { 583 {
@@ -649,7 +590,7 @@ void LLFont::setSubImageLuminanceAlpha(const U32 x,
649 U32 i, j; 590 U32 i, j;
650 U32 to_offset; 591 U32 to_offset;
651 U32 from_offset; 592 U32 from_offset;
652 U32 target_width = mRawImagep->getWidth(); 593 U32 target_width = image_raw->getWidth();
653 for (i = 0; i < height; i++) 594 for (i = 0; i < height; i++)
654 { 595 {
655 to_offset = (y + i)*target_width + x; 596 to_offset = (y + i)*target_width + x;