diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llrender/llfont.cpp | 187 |
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 | ||
56 | FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL; | 59 | FT_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 | ||
127 | LLFont::LLFont(LLImageRaw *imagep) | 130 | LLFont::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 | ||
147 | LLFont::~LLFont() | 150 | LLFont::~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 | ||
160 | void 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 | 256 | void LLFont::resetBitmapCache() | |
297 | void 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 | ||
343 | BOOL LLFont::addChar(const llwchar wch) | 298 | BOOL 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 | ||
398 | BOOL LLFont::addGlyphFromFont(LLFont *fontp, const llwchar wch, const U32 glyph_index) | 352 | BOOL 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 | ||
519 | BOOL LLFont::addGlyph(const llwchar wch, const U32 glyph_index) | 453 | BOOL 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 | ||
597 | void LLFont::renderGlyph(const U32 glyph_index) | 531 | void 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 | ||
629 | void LLFont::setSubImageLuminanceAlpha(const U32 x, | 566 | void 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; |