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