rsFont.cpp revision 4f230b31d59b5f17100686bc1416b3b07a4a618d
1 2/* 3 * Copyright (C) 2009 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18#ifndef ANDROID_RS_BUILD_FOR_HOST 19#include "rsContext.h" 20#else 21#include "rsContextHostStub.h" 22#endif 23 24#include "rsFont.h" 25#include "rsProgramFragment.h" 26#include <cutils/properties.h> 27#include FT_BITMAP_H 28 29#include <GLES/gl.h> 30#include <GLES/glext.h> 31#include <GLES2/gl2.h> 32#include <GLES2/gl2ext.h> 33 34using namespace android; 35using namespace android::renderscript; 36 37Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) 38{ 39 mAllocFile = __FILE__; 40 mAllocLine = __LINE__; 41 mInitialized = false; 42 mHasKerning = false; 43 mFace = NULL; 44} 45 46bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi) 47{ 48 if(mInitialized) { 49 LOGE("Reinitialization of fonts not supported"); 50 return false; 51 } 52 53 String8 fontsDir("/fonts/"); 54 String8 fullPath(getenv("ANDROID_ROOT")); 55 fullPath += fontsDir; 56 fullPath += name; 57 58 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace); 59 if(error) { 60 LOGE("Unable to initialize font %s", fullPath.string()); 61 return false; 62 } 63 64 mFontName = name; 65 mFontSize = fontSize; 66 mDpi = dpi; 67 68 error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0); 69 if(error) { 70 LOGE("Unable to set font size on %s", fullPath.string()); 71 return false; 72 } 73 74 mHasKerning = FT_HAS_KERNING(mFace); 75 76 mInitialized = true; 77 return true; 78} 79 80void Font::invalidateTextureCache() 81{ 82 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { 83 mCachedGlyphs.valueAt(i)->mIsValid = false; 84 } 85} 86 87void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) 88{ 89 FontState *state = &mRSC->mStateFont; 90 91 int32_t nPenX = x + glyph->mBitmapLeft; 92 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight; 93 94 float u1 = glyph->mBitmapMinU; 95 float u2 = glyph->mBitmapMaxU; 96 float v1 = glyph->mBitmapMinV; 97 float v2 = glyph->mBitmapMaxV; 98 99 int32_t width = (int32_t) glyph->mBitmapWidth; 100 int32_t height = (int32_t) glyph->mBitmapHeight; 101 102 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2, 103 nPenX + width, nPenY, 0, u2, v2, 104 nPenX + width, nPenY - height, 0, u2, v1, 105 nPenX, nPenY - height, 0, u1, v1); 106} 107 108void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y, 109 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) { 110 int32_t nPenX = x + glyph->mBitmapLeft; 111 int32_t nPenY = y + glyph->mBitmapTop; 112 113 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth; 114 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight; 115 116 FontState *state = &mRSC->mStateFont; 117 uint32_t cacheWidth = state->getCacheTextureType()->getDimX(); 118 const uint8_t* cacheBuffer = state->getTextTextureData(); 119 120 uint32_t cacheX = 0, cacheY = 0; 121 int32_t bX = 0, bY = 0; 122 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) { 123 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) { 124 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) { 125 LOGE("Skipping invalid index"); 126 continue; 127 } 128 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX]; 129 bitmap[bY * bitmapW + bX] = tempCol; 130 } 131 } 132 133} 134 135void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) { 136 int32_t nPenX = x + glyph->mBitmapLeft; 137 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight; 138 139 int32_t width = (int32_t) glyph->mBitmapWidth; 140 int32_t height = (int32_t) glyph->mBitmapHeight; 141 142 if (bounds->bottom > nPenY) { 143 bounds->bottom = nPenY; 144 } 145 if (bounds->left > nPenX) { 146 bounds->left = nPenX; 147 } 148 if (bounds->right < nPenX + width) { 149 bounds->right = nPenX + width; 150 } 151 if (bounds->top < nPenY + height) { 152 bounds->top = nPenY + height; 153 } 154} 155 156void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y, 157 uint32_t start, int32_t numGlyphs, 158 RenderMode mode, Rect *bounds, 159 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) 160{ 161 if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) { 162 return; 163 } 164 165 if(mode == Font::MEASURE) { 166 if (bounds == NULL) { 167 LOGE("No return rectangle provided to measure text"); 168 return; 169 } 170 // Reset min and max of the bounding box to something large 171 bounds->set(1e6, -1e6, -1e6, 1e6); 172 } 173 174 int32_t penX = x, penY = y; 175 int32_t glyphsLeft = 1; 176 if(numGlyphs > 0) { 177 glyphsLeft = numGlyphs; 178 } 179 180 size_t index = start; 181 size_t nextIndex = 0; 182 183 while (glyphsLeft > 0) { 184 185 int32_t utfChar = utf32_at(text, len, index, &nextIndex); 186 187 // Reached the end of the string or encountered 188 if(utfChar < 0) { 189 break; 190 } 191 192 // Move to the next character in the array 193 index = nextIndex; 194 195 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar); 196 197 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 198 if(cachedGlyph->mIsValid) { 199 switch(mode) { 200 case FRAMEBUFFER: 201 drawCachedGlyph(cachedGlyph, penX, penY); 202 break; 203 case BITMAP: 204 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH); 205 break; 206 case MEASURE: 207 measureCachedGlyph(cachedGlyph, penX, penY, bounds); 208 break; 209 } 210 } 211 212 penX += (cachedGlyph->mAdvance.x >> 6); 213 214 // If we were given a specific number of glyphs, decrement 215 if(numGlyphs > 0) { 216 glyphsLeft --; 217 } 218 } 219} 220 221Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) { 222 223 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar); 224 if(cachedGlyph == NULL) { 225 cachedGlyph = cacheGlyph((uint32_t)utfChar); 226 } 227 // Is the glyph still in texture cache? 228 if(!cachedGlyph->mIsValid) { 229 updateGlyphCache(cachedGlyph); 230 } 231 232 return cachedGlyph; 233} 234 235void Font::updateGlyphCache(CachedGlyphInfo *glyph) 236{ 237 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER ); 238 if(error) { 239 LOGE("Couldn't load glyph."); 240 return; 241 } 242 243 glyph->mAdvance = mFace->glyph->advance; 244 glyph->mBitmapLeft = mFace->glyph->bitmap_left; 245 glyph->mBitmapTop = mFace->glyph->bitmap_top; 246 247 FT_Bitmap *bitmap = &mFace->glyph->bitmap; 248 249 // Now copy the bitmap into the cache texture 250 uint32_t startX = 0; 251 uint32_t startY = 0; 252 253 // Let the font state figure out where to put the bitmap 254 FontState *state = &mRSC->mStateFont; 255 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY); 256 257 if(!glyph->mIsValid) { 258 return; 259 } 260 261 uint32_t endX = startX + bitmap->width; 262 uint32_t endY = startY + bitmap->rows; 263 264 glyph->mBitmapMinX = startX; 265 glyph->mBitmapMinY = startY; 266 glyph->mBitmapWidth = bitmap->width; 267 glyph->mBitmapHeight = bitmap->rows; 268 269 uint32_t cacheWidth = state->getCacheTextureType()->getDimX(); 270 uint32_t cacheHeight = state->getCacheTextureType()->getDimY(); 271 272 glyph->mBitmapMinU = (float)startX / (float)cacheWidth; 273 glyph->mBitmapMinV = (float)startY / (float)cacheHeight; 274 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth; 275 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight; 276} 277 278Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) 279{ 280 CachedGlyphInfo *newGlyph = new CachedGlyphInfo(); 281 mCachedGlyphs.add(glyph, newGlyph); 282 283 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph); 284 newGlyph->mIsValid = false; 285 286 updateGlyphCache(newGlyph); 287 288 return newGlyph; 289} 290 291Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi) 292{ 293 rsc->mStateFont.checkInit(); 294 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts; 295 296 for(uint32_t i = 0; i < activeFonts.size(); i ++) { 297 Font *ithFont = activeFonts[i]; 298 if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) { 299 return ithFont; 300 } 301 } 302 303 Font *newFont = new Font(rsc); 304 bool isInitialized = newFont->init(name, fontSize, dpi); 305 if(isInitialized) { 306 activeFonts.push(newFont); 307 rsc->mStateFont.precacheLatin(newFont); 308 return newFont; 309 } 310 311 delete newFont; 312 return NULL; 313 314} 315 316Font::~Font() 317{ 318 if(mFace) { 319 FT_Done_Face(mFace); 320 } 321 322 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) { 323 if (mRSC->mStateFont.mActiveFonts[ct] == this) { 324 mRSC->mStateFont.mActiveFonts.removeAt(ct); 325 break; 326 } 327 } 328 329 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { 330 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i); 331 delete glyph; 332 } 333} 334 335FontState::FontState() 336{ 337 mInitialized = false; 338 mMaxNumberOfQuads = 1024; 339 mCurrentQuadIndex = 0; 340 mRSC = NULL; 341 mLibrary = NULL; 342 343 // Get the renderer properties 344 char property[PROPERTY_VALUE_MAX]; 345 346 // Get the gamma 347 float gamma = DEFAULT_TEXT_GAMMA; 348 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) { 349 LOGD(" Setting text gamma to %s", property); 350 gamma = atof(property); 351 } else { 352 LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA); 353 } 354 355 // Get the black gamma threshold 356 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD; 357 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) { 358 LOGD(" Setting text black gamma threshold to %s", property); 359 blackThreshold = atoi(property); 360 } else { 361 LOGD(" Using default text black gamma threshold of %d", 362 DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD); 363 } 364 mBlackThreshold = (float)(blackThreshold) / 255.0f; 365 366 // Get the white gamma threshold 367 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD; 368 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) { 369 LOGD(" Setting text white gamma threshold to %s", property); 370 whiteThreshold = atoi(property); 371 } else { 372 LOGD(" Using default white black gamma threshold of %d", 373 DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD); 374 } 375 mWhiteThreshold = (float)(whiteThreshold) / 255.0f; 376 377 // Compute the gamma tables 378 mBlackGamma = gamma; 379 mWhiteGamma = 1.0f / gamma; 380 381 setFontColor(0.1f, 0.1f, 0.1f, 1.0f); 382} 383 384FontState::~FontState() 385{ 386 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 387 delete mCacheLines[i]; 388 } 389 390 rsAssert(!mActiveFonts.size()); 391} 392 393FT_Library FontState::getLib() 394{ 395 if(!mLibrary) { 396 FT_Error error = FT_Init_FreeType(&mLibrary); 397 if(error) { 398 LOGE("Unable to initialize freetype"); 399 return NULL; 400 } 401 } 402 403 return mLibrary; 404} 405 406void FontState::init(Context *rsc) 407{ 408 mRSC = rsc; 409} 410 411void FontState::flushAllAndInvalidate() 412{ 413 if(mCurrentQuadIndex != 0) { 414 issueDrawCommand(); 415 mCurrentQuadIndex = 0; 416 } 417 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) { 418 mActiveFonts[i]->invalidateTextureCache(); 419 } 420 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 421 mCacheLines[i]->mCurrentCol = 0; 422 } 423} 424 425bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) 426{ 427 // If the glyph is too tall, don't cache it 428 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) { 429 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); 430 return false; 431 } 432 433 // Now copy the bitmap into the cache texture 434 uint32_t startX = 0; 435 uint32_t startY = 0; 436 437 bool bitmapFit = false; 438 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 439 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); 440 if(bitmapFit) { 441 break; 442 } 443 } 444 445 // If the new glyph didn't fit, flush the state so far and invalidate everything 446 if(!bitmapFit) { 447 flushAllAndInvalidate(); 448 449 // Try to fit it again 450 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 451 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); 452 if(bitmapFit) { 453 break; 454 } 455 } 456 457 // if we still don't fit, something is wrong and we shouldn't draw 458 if(!bitmapFit) { 459 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); 460 return false; 461 } 462 } 463 464 *retOriginX = startX; 465 *retOriginY = startY; 466 467 uint32_t endX = startX + bitmap->width; 468 uint32_t endY = startY + bitmap->rows; 469 470 uint32_t cacheWidth = getCacheTextureType()->getDimX(); 471 472 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr(); 473 uint8_t *bitmapBuffer = bitmap->buffer; 474 475 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 476 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) { 477 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) { 478 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX]; 479 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol; 480 } 481 } 482 483 // This will dirty the texture and the shader so next time 484 // we draw it will upload the data 485 mTextTexture->deferedUploadToTexture(mRSC, false, 0); 486 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get()); 487 488 // Some debug code 489 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 490 LOGE("Cache Line: H: %u Empty Space: %f", 491 mCacheLines[i]->mMaxHeight, 492 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f); 493 494 }*/ 495 496 return true; 497} 498 499void FontState::initRenderState() 500{ 501 String8 shaderString("varying vec2 varTex0;\n"); 502 shaderString.append("void main() {\n"); 503 shaderString.append(" lowp vec4 col = UNI_Color;\n"); 504 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"); 505 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n"); 506 shaderString.append(" gl_FragColor = col;\n"); 507 shaderString.append("}\n"); 508 509 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4); 510 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1); 511 mRSC->mStateElement.elementBuilderBegin(); 512 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1); 513 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1); 514 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC); 515 516 Type *inputType = new Type(mRSC); 517 inputType->setElement(constInput); 518 inputType->setDimX(1); 519 inputType->compute(); 520 521 uint32_t tmp[4]; 522 tmp[0] = RS_PROGRAM_PARAM_CONSTANT; 523 tmp[1] = (uint32_t)inputType; 524 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT; 525 tmp[3] = 1; 526 527 mFontShaderFConstant.set(new Allocation(mRSC, inputType)); 528 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), 529 shaderString.length(), tmp, 4); 530 mFontShaderF.set(pf); 531 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0); 532 533 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST, 534 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP); 535 mFontSampler.set(sampler); 536 mFontShaderF->bindSampler(mRSC, 0, sampler); 537 538 ProgramStore *fontStore = new ProgramStore(mRSC); 539 mFontProgramStore.set(fontStore); 540 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS); 541 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA); 542 mFontProgramStore->setDitherEnable(false); 543 mFontProgramStore->setDepthMask(false); 544} 545 546void FontState::initTextTexture() 547{ 548 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1); 549 550 // We will allocate a texture to initially hold 32 character bitmaps 551 Type *texType = new Type(mRSC); 552 texType->setElement(alphaElem); 553 texType->setDimX(1024); 554 texType->setDimY(256); 555 texType->compute(); 556 557 Allocation *cacheAlloc = new Allocation(mRSC, texType); 558 mTextTexture.set(cacheAlloc); 559 mTextTexture->deferedUploadToTexture(mRSC, false, 0); 560 561 // Split up our cache texture into lines of certain widths 562 int32_t nextLine = 0; 563 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0)); 564 nextLine += mCacheLines.top()->mMaxHeight; 565 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); 566 nextLine += mCacheLines.top()->mMaxHeight; 567 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); 568 nextLine += mCacheLines.top()->mMaxHeight; 569 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); 570 nextLine += mCacheLines.top()->mMaxHeight; 571 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); 572 nextLine += mCacheLines.top()->mMaxHeight; 573 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0)); 574 nextLine += mCacheLines.top()->mMaxHeight; 575 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0)); 576} 577 578// Avoid having to reallocate memory and render quad by quad 579void FontState::initVertexArrayBuffers() 580{ 581 // Now lets write index data 582 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1); 583 Type *indexType = new Type(mRSC); 584 uint32_t numIndicies = mMaxNumberOfQuads * 6; 585 indexType->setDimX(numIndicies); 586 indexType->setElement(indexElem); 587 indexType->compute(); 588 589 Allocation *indexAlloc = new Allocation(mRSC, indexType); 590 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr(); 591 592 // Four verts, two triangles , six indices per quad 593 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) { 594 int32_t i6 = i * 6; 595 int32_t i4 = i * 4; 596 597 indexPtr[i6 + 0] = i4 + 0; 598 indexPtr[i6 + 1] = i4 + 1; 599 indexPtr[i6 + 2] = i4 + 2; 600 601 indexPtr[i6 + 3] = i4 + 0; 602 indexPtr[i6 + 4] = i4 + 2; 603 indexPtr[i6 + 5] = i4 + 3; 604 } 605 606 indexAlloc->deferedUploadToBufferObject(mRSC); 607 mIndexBuffer.set(indexAlloc); 608 609 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3); 610 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2); 611 612 const Element *elemArray[2]; 613 elemArray[0] = posElem; 614 elemArray[1] = texElem; 615 616 String8 posName("position"); 617 String8 texName("texture0"); 618 619 const char *nameArray[2]; 620 nameArray[0] = posName.string(); 621 nameArray[1] = texName.string(); 622 size_t lengths[2]; 623 lengths[0] = posName.size(); 624 lengths[1] = texName.size(); 625 uint32_t arraySizes[2] = {1, 1}; 626 627 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes); 628 629 Type *vertexDataType = new Type(mRSC); 630 vertexDataType->setDimX(mMaxNumberOfQuads * 4); 631 vertexDataType->setElement(vertexDataElem); 632 vertexDataType->compute(); 633 634 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType); 635 mTextMeshPtr = (float*)vertexAlloc->getPtr(); 636 637 mVertexArray.set(vertexAlloc); 638} 639 640// We don't want to allocate anything unless we actually draw text 641void FontState::checkInit() 642{ 643 if(mInitialized) { 644 return; 645 } 646 647 initTextTexture(); 648 initRenderState(); 649 650 initVertexArrayBuffers(); 651 652 // We store a string with letters in a rough frequency of occurrence 653 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq"); 654 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ"); 655 mLatinPrecache += String8(",.?!()-+@;:`'"); 656 mLatinPrecache += String8("0123456789"); 657 658 mInitialized = true; 659} 660 661void FontState::issueDrawCommand() { 662 663 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex()); 664 mRSC->setVertex(mRSC->getDefaultProgramVertex()); 665 666 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster()); 667 mRSC->setRaster(mRSC->getDefaultProgramRaster()); 668 669 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment()); 670 mRSC->setFragment(mFontShaderF.get()); 671 672 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore()); 673 mRSC->setFragmentStore(mFontProgramStore.get()); 674 675 if(mConstantsDirty) { 676 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants)); 677 mConstantsDirty = false; 678 } 679 680 if (!mRSC->setupCheck()) { 681 mRSC->setVertex((ProgramVertex *)tmpV.get()); 682 mRSC->setRaster((ProgramRaster *)tmpR.get()); 683 mRSC->setFragment((ProgramFragment *)tmpF.get()); 684 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 685 return; 686 } 687 688 float *vtx = (float*)mVertexArray->getPtr(); 689 float *tex = vtx + 3; 690 691 VertexArray va; 692 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position"); 693 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0"); 694 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache); 695 696 mIndexBuffer->uploadCheck(mRSC); 697 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); 698 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0)); 699 700 // Reset the state 701 mRSC->setVertex((ProgramVertex *)tmpV.get()); 702 mRSC->setRaster((ProgramRaster *)tmpR.get()); 703 mRSC->setFragment((ProgramFragment *)tmpF.get()); 704 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 705} 706 707void FontState::appendMeshQuad(float x1, float y1, float z1, 708 float u1, float v1, 709 float x2, float y2, float z2, 710 float u2, float v2, 711 float x3, float y3, float z3, 712 float u3, float v3, 713 float x4, float y4, float z4, 714 float u4, float v4) 715{ 716 const uint32_t vertsPerQuad = 4; 717 const uint32_t floatsPerVert = 5; 718 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 719 720 // Cull things that are off the screen 721 float width = (float)mRSC->getWidth(); 722 float height = (float)mRSC->getHeight(); 723 724 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) { 725 return; 726 } 727 728 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1); 729 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2); 730 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3); 731 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/ 732 733 (*currentPos++) = x1; 734 (*currentPos++) = y1; 735 (*currentPos++) = z1; 736 (*currentPos++) = u1; 737 (*currentPos++) = v1; 738 739 (*currentPos++) = x2; 740 (*currentPos++) = y2; 741 (*currentPos++) = z2; 742 (*currentPos++) = u2; 743 (*currentPos++) = v2; 744 745 (*currentPos++) = x3; 746 (*currentPos++) = y3; 747 (*currentPos++) = z3; 748 (*currentPos++) = u3; 749 (*currentPos++) = v3; 750 751 (*currentPos++) = x4; 752 (*currentPos++) = y4; 753 (*currentPos++) = z4; 754 (*currentPos++) = u4; 755 (*currentPos++) = v4; 756 757 mCurrentQuadIndex ++; 758 759 if(mCurrentQuadIndex == mMaxNumberOfQuads) { 760 issueDrawCommand(); 761 mCurrentQuadIndex = 0; 762 } 763} 764 765uint32_t FontState::getRemainingCacheCapacity() { 766 uint32_t remainingCapacity = 0; 767 uint32_t totalPixels = 0; 768 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 769 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); 770 totalPixels += mCacheLines[i]->mMaxWidth; 771 } 772 remainingCapacity = (remainingCapacity * 100) / totalPixels; 773 return remainingCapacity; 774} 775 776void FontState::precacheLatin(Font *font) { 777 // Remaining capacity is measured in % 778 uint32_t remainingCapacity = getRemainingCacheCapacity(); 779 uint32_t precacheIdx = 0; 780 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { 781 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]); 782 remainingCapacity = getRemainingCacheCapacity(); 783 precacheIdx ++; 784 } 785} 786 787 788void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y, 789 uint32_t startIndex, int32_t numGlyphs, 790 Font::RenderMode mode, 791 Font::Rect *bounds, 792 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) 793{ 794 checkInit(); 795 796 // Render code here 797 Font *currentFont = mRSC->getFont(); 798 if(!currentFont) { 799 if(!mDefault.get()) { 800 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96)); 801 } 802 currentFont = mDefault.get(); 803 } 804 if(!currentFont) { 805 LOGE("Unable to initialize any fonts"); 806 return; 807 } 808 809 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs, 810 mode, bounds, bitmap, bitmapW, bitmapH); 811 812 if(mCurrentQuadIndex != 0) { 813 issueDrawCommand(); 814 mCurrentQuadIndex = 0; 815 } 816} 817 818void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) { 819 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds); 820} 821 822void FontState::setFontColor(float r, float g, float b, float a) { 823 mConstants.mFontColor[0] = r; 824 mConstants.mFontColor[1] = g; 825 mConstants.mFontColor[2] = b; 826 mConstants.mFontColor[3] = a; 827 828 mConstants.mGamma = 1.0f; 829 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f; 830 if (luminance <= mBlackThreshold) { 831 mConstants.mGamma = mBlackGamma; 832 } else if (luminance >= mWhiteThreshold) { 833 mConstants.mGamma = mWhiteGamma; 834 } 835 836 mConstantsDirty = true; 837} 838 839void FontState::getFontColor(float *r, float *g, float *b, float *a) const { 840 *r = mConstants.mFontColor[0]; 841 *g = mConstants.mFontColor[1]; 842 *b = mConstants.mFontColor[2]; 843 *a = mConstants.mFontColor[3]; 844} 845 846void FontState::deinit(Context *rsc) 847{ 848 mInitialized = false; 849 850 mFontShaderFConstant.clear(); 851 852 mIndexBuffer.clear(); 853 mVertexArray.clear(); 854 855 mFontShaderF.clear(); 856 mFontSampler.clear(); 857 mFontProgramStore.clear(); 858 859 mTextTexture.clear(); 860 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 861 delete mCacheLines[i]; 862 } 863 mCacheLines.clear(); 864 865 mDefault.clear(); 866 867 Vector<Font*> fontsToDereference = mActiveFonts; 868 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) { 869 fontsToDereference[i]->zeroUserRef(); 870 } 871 872 if(mLibrary) { 873 FT_Done_FreeType( mLibrary ); 874 mLibrary = NULL; 875 } 876} 877 878namespace android { 879namespace renderscript { 880 881RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) 882{ 883 Font *newFont = Font::create(rsc, name, fontSize, dpi); 884 if(newFont) { 885 newFont->incUserRef(); 886 } 887 return newFont; 888} 889 890} // renderscript 891} // android 892