rsFont.cpp revision 09c67356bbeee0a97a20a06c95b66756838cb541
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 setFontColor(0.1f, 0.1f, 0.1f, 1.0f); 343 344 // Get the renderer properties 345 char property[PROPERTY_VALUE_MAX]; 346 347 // Get the gamma 348 float gamma = DEFAULT_TEXT_GAMMA; 349 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) { 350 LOGD(" Setting text gamma to %s", property); 351 gamma = atof(property); 352 } else { 353 LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA); 354 } 355 356 // Get the black gamma threshold 357 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD; 358 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) { 359 LOGD(" Setting text black gamma threshold to %s", property); 360 blackThreshold = atoi(property); 361 } else { 362 LOGD(" Using default text black gamma threshold of %d", 363 DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD); 364 } 365 mBlackThreshold = (float)(blackThreshold) / 255.0f; 366 367 // Get the white gamma threshold 368 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD; 369 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) { 370 LOGD(" Setting text white gamma threshold to %s", property); 371 whiteThreshold = atoi(property); 372 } else { 373 LOGD(" Using default white black gamma threshold of %d", 374 DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD); 375 } 376 mWhiteThreshold = (float)(whiteThreshold) / 255.0f; 377 378 // Compute the gamma tables 379 mBlackGamma = gamma; 380 mWhiteGamma = 1.0f / gamma; 381} 382 383FontState::~FontState() 384{ 385 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 386 delete mCacheLines[i]; 387 } 388 389 rsAssert(!mActiveFonts.size()); 390} 391 392FT_Library FontState::getLib() 393{ 394 if(!mLibrary) { 395 FT_Error error = FT_Init_FreeType(&mLibrary); 396 if(error) { 397 LOGE("Unable to initialize freetype"); 398 return NULL; 399 } 400 } 401 402 return mLibrary; 403} 404 405void FontState::init(Context *rsc) 406{ 407 mRSC = rsc; 408} 409 410void FontState::flushAllAndInvalidate() 411{ 412 if(mCurrentQuadIndex != 0) { 413 issueDrawCommand(); 414 mCurrentQuadIndex = 0; 415 } 416 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) { 417 mActiveFonts[i]->invalidateTextureCache(); 418 } 419 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 420 mCacheLines[i]->mCurrentCol = 0; 421 } 422} 423 424bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) 425{ 426 // If the glyph is too tall, don't cache it 427 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) { 428 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); 429 return false; 430 } 431 432 // Now copy the bitmap into the cache texture 433 uint32_t startX = 0; 434 uint32_t startY = 0; 435 436 bool bitmapFit = false; 437 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 438 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); 439 if(bitmapFit) { 440 break; 441 } 442 } 443 444 // If the new glyph didn't fit, flush the state so far and invalidate everything 445 if(!bitmapFit) { 446 flushAllAndInvalidate(); 447 448 // Try to fit it again 449 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 450 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); 451 if(bitmapFit) { 452 break; 453 } 454 } 455 456 // if we still don't fit, something is wrong and we shouldn't draw 457 if(!bitmapFit) { 458 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); 459 return false; 460 } 461 } 462 463 *retOriginX = startX; 464 *retOriginY = startY; 465 466 uint32_t endX = startX + bitmap->width; 467 uint32_t endY = startY + bitmap->rows; 468 469 uint32_t cacheWidth = getCacheTextureType()->getDimX(); 470 471 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr(); 472 uint8_t *bitmapBuffer = bitmap->buffer; 473 474 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 475 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) { 476 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) { 477 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX]; 478 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol; 479 } 480 } 481 482 // This will dirty the texture and the shader so next time 483 // we draw it will upload the data 484 mTextTexture->deferedUploadToTexture(mRSC, false, 0); 485 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get()); 486 487 // Some debug code 488 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 489 LOGE("Cache Line: H: %u Empty Space: %f", 490 mCacheLines[i]->mMaxHeight, 491 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f); 492 493 }*/ 494 495 return true; 496} 497 498void FontState::initRenderState() 499{ 500 String8 shaderString("varying vec4 varTex0;\n"); 501 shaderString.append("void main() {\n"); 502 shaderString.append(" lowp vec4 col = UNI_Color;\n"); 503 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"); 504 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n"); 505 shaderString.append(" gl_FragColor = col;\n"); 506 shaderString.append("}\n"); 507 508 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4); 509 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1); 510 mRSC->mStateElement.elementBuilderBegin(); 511 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1); 512 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1); 513 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC); 514 515 Type *inputType = new Type(mRSC); 516 inputType->setElement(constInput); 517 inputType->setDimX(1); 518 inputType->compute(); 519 520 uint32_t tmp[4]; 521 tmp[0] = RS_PROGRAM_PARAM_CONSTANT; 522 tmp[1] = (uint32_t)inputType; 523 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT; 524 tmp[3] = 1; 525 526 mFontShaderFConstant.set(new Allocation(mRSC, inputType)); 527 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), 528 shaderString.length(), tmp, 4); 529 mFontShaderF.set(pf); 530 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0); 531 532 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST, 533 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP); 534 mFontSampler.set(sampler); 535 mFontShaderF->bindSampler(mRSC, 0, sampler); 536 537 ProgramStore *fontStore = new ProgramStore(mRSC); 538 mFontProgramStore.set(fontStore); 539 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS); 540 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA); 541 mFontProgramStore->setDitherEnable(false); 542 mFontProgramStore->setDepthMask(false); 543} 544 545void FontState::initTextTexture() 546{ 547 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1); 548 549 // We will allocate a texture to initially hold 32 character bitmaps 550 Type *texType = new Type(mRSC); 551 texType->setElement(alphaElem); 552 texType->setDimX(1024); 553 texType->setDimY(256); 554 texType->compute(); 555 556 Allocation *cacheAlloc = new Allocation(mRSC, texType); 557 mTextTexture.set(cacheAlloc); 558 mTextTexture->deferedUploadToTexture(mRSC, false, 0); 559 560 // Split up our cache texture into lines of certain widths 561 int32_t nextLine = 0; 562 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0)); 563 nextLine += mCacheLines.top()->mMaxHeight; 564 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); 565 nextLine += mCacheLines.top()->mMaxHeight; 566 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); 567 nextLine += mCacheLines.top()->mMaxHeight; 568 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); 569 nextLine += mCacheLines.top()->mMaxHeight; 570 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); 571 nextLine += mCacheLines.top()->mMaxHeight; 572 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0)); 573 nextLine += mCacheLines.top()->mMaxHeight; 574 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0)); 575} 576 577// Avoid having to reallocate memory and render quad by quad 578void FontState::initVertexArrayBuffers() 579{ 580 // Now lets write index data 581 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1); 582 Type *indexType = new Type(mRSC); 583 uint32_t numIndicies = mMaxNumberOfQuads * 6; 584 indexType->setDimX(numIndicies); 585 indexType->setElement(indexElem); 586 indexType->compute(); 587 588 Allocation *indexAlloc = new Allocation(mRSC, indexType); 589 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr(); 590 591 // Four verts, two triangles , six indices per quad 592 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) { 593 int32_t i6 = i * 6; 594 int32_t i4 = i * 4; 595 596 indexPtr[i6 + 0] = i4 + 0; 597 indexPtr[i6 + 1] = i4 + 1; 598 indexPtr[i6 + 2] = i4 + 2; 599 600 indexPtr[i6 + 3] = i4 + 0; 601 indexPtr[i6 + 4] = i4 + 2; 602 indexPtr[i6 + 5] = i4 + 3; 603 } 604 605 indexAlloc->deferedUploadToBufferObject(mRSC); 606 mIndexBuffer.set(indexAlloc); 607 608 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3); 609 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2); 610 611 const Element *elemArray[2]; 612 elemArray[0] = posElem; 613 elemArray[1] = texElem; 614 615 String8 posName("position"); 616 String8 texName("texture0"); 617 618 const char *nameArray[2]; 619 nameArray[0] = posName.string(); 620 nameArray[1] = texName.string(); 621 size_t lengths[2]; 622 lengths[0] = posName.size(); 623 lengths[1] = texName.size(); 624 uint32_t arraySizes[2] = {1, 1}; 625 626 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes); 627 628 Type *vertexDataType = new Type(mRSC); 629 vertexDataType->setDimX(mMaxNumberOfQuads * 4); 630 vertexDataType->setElement(vertexDataElem); 631 vertexDataType->compute(); 632 633 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType); 634 mTextMeshPtr = (float*)vertexAlloc->getPtr(); 635 636 mVertexArray.set(vertexAlloc); 637} 638 639// We don't want to allocate anything unless we actually draw text 640void FontState::checkInit() 641{ 642 if(mInitialized) { 643 return; 644 } 645 646 initTextTexture(); 647 initRenderState(); 648 649 initVertexArrayBuffers(); 650 651 // We store a string with letters in a rough frequency of occurrence 652 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq"); 653 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ"); 654 mLatinPrecache += String8(",.?!()-+@;:`'"); 655 mLatinPrecache += String8("0123456789"); 656 657 mInitialized = true; 658} 659 660void FontState::issueDrawCommand() { 661 662 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex()); 663 mRSC->setVertex(mRSC->getDefaultProgramVertex()); 664 665 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster()); 666 mRSC->setRaster(mRSC->getDefaultProgramRaster()); 667 668 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment()); 669 mRSC->setFragment(mFontShaderF.get()); 670 671 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore()); 672 mRSC->setFragmentStore(mFontProgramStore.get()); 673 674 if(mConstantsDirty) { 675 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants)); 676 mConstantsDirty = false; 677 } 678 679 if (!mRSC->setupCheck()) { 680 mRSC->setVertex((ProgramVertex *)tmpV.get()); 681 mRSC->setRaster((ProgramRaster *)tmpR.get()); 682 mRSC->setFragment((ProgramFragment *)tmpF.get()); 683 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 684 return; 685 } 686 687 float *vtx = (float*)mVertexArray->getPtr(); 688 float *tex = vtx + 3; 689 690 VertexArray va; 691 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position"); 692 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0"); 693 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache); 694 695 mIndexBuffer->uploadCheck(mRSC); 696 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); 697 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0)); 698 699 // Reset the state 700 mRSC->setVertex((ProgramVertex *)tmpV.get()); 701 mRSC->setRaster((ProgramRaster *)tmpR.get()); 702 mRSC->setFragment((ProgramFragment *)tmpF.get()); 703 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 704} 705 706void FontState::appendMeshQuad(float x1, float y1, float z1, 707 float u1, float v1, 708 float x2, float y2, float z2, 709 float u2, float v2, 710 float x3, float y3, float z3, 711 float u3, float v3, 712 float x4, float y4, float z4, 713 float u4, float v4) 714{ 715 const uint32_t vertsPerQuad = 4; 716 const uint32_t floatsPerVert = 5; 717 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 718 719 // Cull things that are off the screen 720 float width = (float)mRSC->getWidth(); 721 float height = (float)mRSC->getHeight(); 722 723 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) { 724 return; 725 } 726 727 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1); 728 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2); 729 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3); 730 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/ 731 732 (*currentPos++) = x1; 733 (*currentPos++) = y1; 734 (*currentPos++) = z1; 735 (*currentPos++) = u1; 736 (*currentPos++) = v1; 737 738 (*currentPos++) = x2; 739 (*currentPos++) = y2; 740 (*currentPos++) = z2; 741 (*currentPos++) = u2; 742 (*currentPos++) = v2; 743 744 (*currentPos++) = x3; 745 (*currentPos++) = y3; 746 (*currentPos++) = z3; 747 (*currentPos++) = u3; 748 (*currentPos++) = v3; 749 750 (*currentPos++) = x4; 751 (*currentPos++) = y4; 752 (*currentPos++) = z4; 753 (*currentPos++) = u4; 754 (*currentPos++) = v4; 755 756 mCurrentQuadIndex ++; 757 758 if(mCurrentQuadIndex == mMaxNumberOfQuads) { 759 issueDrawCommand(); 760 mCurrentQuadIndex = 0; 761 } 762} 763 764uint32_t FontState::getRemainingCacheCapacity() { 765 uint32_t remainingCapacity = 0; 766 uint32_t totalPixels = 0; 767 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 768 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); 769 totalPixels += mCacheLines[i]->mMaxWidth; 770 } 771 remainingCapacity = (remainingCapacity * 100) / totalPixels; 772 return remainingCapacity; 773} 774 775void FontState::precacheLatin(Font *font) { 776 // Remaining capacity is measured in % 777 uint32_t remainingCapacity = getRemainingCacheCapacity(); 778 uint32_t precacheIdx = 0; 779 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { 780 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]); 781 remainingCapacity = getRemainingCacheCapacity(); 782 precacheIdx ++; 783 } 784} 785 786 787void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y, 788 uint32_t startIndex, int32_t numGlyphs, 789 Font::RenderMode mode, 790 Font::Rect *bounds, 791 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) 792{ 793 checkInit(); 794 795 // Render code here 796 Font *currentFont = mRSC->getFont(); 797 if(!currentFont) { 798 if(!mDefault.get()) { 799 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96)); 800 } 801 currentFont = mDefault.get(); 802 } 803 if(!currentFont) { 804 LOGE("Unable to initialize any fonts"); 805 return; 806 } 807 808 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs, 809 mode, bounds, bitmap, bitmapW, bitmapH); 810 811 if(mCurrentQuadIndex != 0) { 812 issueDrawCommand(); 813 mCurrentQuadIndex = 0; 814 } 815} 816 817void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) { 818 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds); 819} 820 821void FontState::setFontColor(float r, float g, float b, float a) { 822 mConstants.mFontColor[0] = r; 823 mConstants.mFontColor[1] = g; 824 mConstants.mFontColor[2] = b; 825 mConstants.mFontColor[3] = a; 826 827 mConstants.mGamma = 1.0f; 828 const int32_t luminance = (r * 2.0f + g * 5.0f + b) / 8.0f; 829 if (luminance <= mBlackThreshold) { 830 mConstants.mGamma = mBlackGamma; 831 } else if (luminance >= mWhiteThreshold) { 832 mConstants.mGamma = mWhiteGamma; 833 } 834 mConstantsDirty = true; 835} 836 837void FontState::getFontColor(float *r, float *g, float *b, float *a) const { 838 *r = mConstants.mFontColor[0]; 839 *g = mConstants.mFontColor[1]; 840 *b = mConstants.mFontColor[2]; 841 *a = mConstants.mFontColor[3]; 842} 843 844void FontState::deinit(Context *rsc) 845{ 846 mInitialized = false; 847 848 mFontShaderFConstant.clear(); 849 850 mIndexBuffer.clear(); 851 mVertexArray.clear(); 852 853 mFontShaderF.clear(); 854 mFontSampler.clear(); 855 mFontProgramStore.clear(); 856 857 mTextTexture.clear(); 858 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 859 delete mCacheLines[i]; 860 } 861 mCacheLines.clear(); 862 863 mDefault.clear(); 864 865 Vector<Font*> fontsToDereference = mActiveFonts; 866 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) { 867 fontsToDereference[i]->zeroUserRef(); 868 } 869 870 if(mLibrary) { 871 FT_Done_FreeType( mLibrary ); 872 mLibrary = NULL; 873 } 874} 875 876namespace android { 877namespace renderscript { 878 879RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) 880{ 881 Font *newFont = Font::create(rsc, name, fontSize, dpi); 882 if(newFont) { 883 newFont->incUserRef(); 884 } 885 return newFont; 886} 887 888} // renderscript 889} // android 890