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