123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879 |
- /*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "rsContext.h"
- #include "rs.h"
- #include "rsFont.h"
- #include "rsProgramFragment.h"
- #include "rsMesh.h"
- #ifndef ANDROID_RS_SERIALIZE
- #include <ft2build.h>
- #include FT_FREETYPE_H
- #include FT_BITMAP_H
- #endif //ANDROID_RS_SERIALIZE
- #include <string.h>
- namespace android {
- namespace renderscript {
- Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
- mInitialized = false;
- mHasKerning = false;
- mFace = nullptr;
- }
- bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
- #ifndef ANDROID_RS_SERIALIZE
- if (mInitialized) {
- ALOGE("Reinitialization of fonts not supported");
- return false;
- }
- FT_Error error = 0;
- if (data != nullptr && dataLen > 0) {
- error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
- } else {
- error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
- }
- if (error) {
- ALOGE("Unable to initialize font %s", name);
- return false;
- }
- mFontName = rsuCopyString(name);
- mFontSize = fontSize;
- mDpi = dpi;
- error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
- if (error) {
- ALOGE("Unable to set font size on %s", name);
- return false;
- }
- mHasKerning = FT_HAS_KERNING(mFace);
- mInitialized = true;
- #endif //ANDROID_RS_SERIALIZE
- return true;
- }
- void Font::preDestroy() const {
- auto& activeFonts = mRSC->mStateFont.mActiveFonts;
- for (uint32_t ct = 0; ct < activeFonts.size(); ct++) {
- if (activeFonts[ct] == this) {
- activeFonts.erase(activeFonts.begin() + ct);
- break;
- }
- }
- }
- void Font::invalidateTextureCache() {
- for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
- mCachedGlyphs.valueAt(i)->mIsValid = false;
- }
- }
- void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
- FontState *state = &mRSC->mStateFont;
- int32_t nPenX = x + glyph->mBitmapLeft;
- int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
- float u1 = glyph->mBitmapMinU;
- float u2 = glyph->mBitmapMaxU;
- float v1 = glyph->mBitmapMinV;
- float v2 = glyph->mBitmapMaxV;
- int32_t width = (int32_t) glyph->mBitmapWidth;
- int32_t height = (int32_t) glyph->mBitmapHeight;
- state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
- nPenX + width, nPenY, 0, u2, v2,
- nPenX + width, nPenY - height, 0, u2, v1,
- nPenX, nPenY - height, 0, u1, v1);
- }
- void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
- uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
- int32_t nPenX = x + glyph->mBitmapLeft;
- int32_t nPenY = y + glyph->mBitmapTop;
- uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
- uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
- FontState *state = &mRSC->mStateFont;
- uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
- const uint8_t* cacheBuffer = state->mCacheBuffer;
- uint32_t cacheX = 0, cacheY = 0;
- int32_t bX = 0, bY = 0;
- for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
- for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
- if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
- ALOGE("Skipping invalid index");
- continue;
- }
- uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
- bitmap[bY * bitmapW + bX] = tempCol;
- }
- }
- }
- void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
- int32_t nPenX = x + glyph->mBitmapLeft;
- int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
- int32_t width = (int32_t) glyph->mBitmapWidth;
- int32_t height = (int32_t) glyph->mBitmapHeight;
- // 0, 0 is top left, so bottom is a positive number
- if (bounds->bottom < nPenY) {
- bounds->bottom = nPenY;
- }
- if (bounds->left > nPenX) {
- bounds->left = nPenX;
- }
- if (bounds->right < nPenX + width) {
- bounds->right = nPenX + width;
- }
- if (bounds->top > nPenY - height) {
- bounds->top = nPenY - height;
- }
- }
- void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
- uint32_t start, int32_t numGlyphs,
- RenderMode mode, Rect *bounds,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
- if (!mInitialized || numGlyphs == 0 || text == nullptr || len == 0) {
- return;
- }
- if (mode == Font::MEASURE) {
- if (bounds == nullptr) {
- ALOGE("No return rectangle provided to measure text");
- return;
- }
- // Reset min and max of the bounding box to something large
- bounds->set(1e6, -1e6, 1e6, -1e6);
- }
- int32_t penX = x, penY = y;
- int32_t glyphsLeft = 1;
- if (numGlyphs > 0) {
- glyphsLeft = numGlyphs;
- }
- size_t index = start;
- size_t nextIndex = 0;
- while (glyphsLeft > 0) {
- int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
- // Reached the end of the string or encountered
- if (utfChar < 0) {
- break;
- }
- // Move to the next character in the array
- index = nextIndex;
- CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
- // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
- if (cachedGlyph->mIsValid) {
- switch (mode) {
- case FRAMEBUFFER:
- drawCachedGlyph(cachedGlyph, penX, penY);
- break;
- case BITMAP:
- drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
- break;
- case MEASURE:
- measureCachedGlyph(cachedGlyph, penX, penY, bounds);
- break;
- }
- }
- penX += (cachedGlyph->mAdvanceX >> 6);
- // If we were given a specific number of glyphs, decrement
- if (numGlyphs > 0) {
- glyphsLeft --;
- }
- }
- }
- Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
- CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
- if (cachedGlyph == nullptr) {
- cachedGlyph = cacheGlyph((uint32_t)utfChar);
- }
- // Is the glyph still in texture cache?
- if (!cachedGlyph->mIsValid) {
- updateGlyphCache(cachedGlyph);
- }
- return cachedGlyph;
- }
- void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
- #ifndef ANDROID_RS_SERIALIZE
- FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
- if (error) {
- ALOGE("Couldn't load glyph.");
- return;
- }
- glyph->mAdvanceX = mFace->glyph->advance.x;
- glyph->mAdvanceY = mFace->glyph->advance.y;
- glyph->mBitmapLeft = mFace->glyph->bitmap_left;
- glyph->mBitmapTop = mFace->glyph->bitmap_top;
- FT_Bitmap *bitmap = &mFace->glyph->bitmap;
- // Now copy the bitmap into the cache texture
- uint32_t startX = 0;
- uint32_t startY = 0;
- // Let the font state figure out where to put the bitmap
- FontState *state = &mRSC->mStateFont;
- glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
- if (!glyph->mIsValid) {
- return;
- }
- uint32_t endX = startX + bitmap->width;
- uint32_t endY = startY + bitmap->rows;
- glyph->mBitmapMinX = startX;
- glyph->mBitmapMinY = startY;
- glyph->mBitmapWidth = bitmap->width;
- glyph->mBitmapHeight = bitmap->rows;
- uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
- uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
- glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
- glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
- glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
- glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
- #endif //ANDROID_RS_SERIALIZE
- }
- Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
- CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
- mCachedGlyphs.add(glyph, newGlyph);
- #ifndef ANDROID_RS_SERIALIZE
- newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
- newGlyph->mIsValid = false;
- #endif //ANDROID_RS_SERIALIZE
- updateGlyphCache(newGlyph);
- return newGlyph;
- }
- Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
- const void *data, uint32_t dataLen) {
- rsc->mStateFont.checkInit();
- auto& activeFonts = rsc->mStateFont.mActiveFonts;
- for (uint32_t i = 0; i < activeFonts.size(); i ++) {
- Font *ithFont = activeFonts[i];
- if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
- return ithFont;
- }
- }
- Font *newFont = new Font(rsc);
- bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
- if (isInitialized) {
- activeFonts.push_back(newFont);
- rsc->mStateFont.precacheLatin(newFont);
- return newFont;
- }
- ObjectBase::checkDelete(newFont);
- return nullptr;
- }
- Font::~Font() {
- #ifndef ANDROID_RS_SERIALIZE
- if (mFace) {
- FT_Done_Face(mFace);
- }
- #endif
- for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
- CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
- delete glyph;
- }
- }
- FontState::FontState() {
- mInitialized = false;
- mMaxNumberOfQuads = 1024;
- mCurrentQuadIndex = 0;
- mRSC = nullptr;
- #ifndef ANDROID_RS_SERIALIZE
- mLibrary = nullptr;
- #endif //ANDROID_RS_SERIALIZE
- float gamma = DEFAULT_TEXT_GAMMA;
- int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
- int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
- #ifdef __ANDROID__
- // Get the renderer properties
- char property[PROP_VALUE_MAX];
- // Get the gamma
- if (property_get(PROPERTY_TEXT_GAMMA, property, nullptr) > 0) {
- gamma = atof(property);
- }
- // Get the black gamma threshold
- if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, nullptr) > 0) {
- blackThreshold = atoi(property);
- }
- // Get the white gamma threshold
- if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, nullptr) > 0) {
- whiteThreshold = atoi(property);
- }
- #endif
- mBlackThreshold = (float)(blackThreshold) / 255.0f;
- mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
- // Compute the gamma tables
- mBlackGamma = gamma;
- mWhiteGamma = 1.0f / gamma;
- setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
- }
- FontState::~FontState() {
- for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
- delete mCacheLines[i];
- }
- rsAssert(!mActiveFonts.size());
- }
- #ifndef ANDROID_RS_SERIALIZE
- FT_Library FontState::getLib() {
- if (!mLibrary) {
- FT_Error error = FT_Init_FreeType(&mLibrary);
- if (error) {
- ALOGE("Unable to initialize freetype");
- return nullptr;
- }
- }
- return mLibrary;
- }
- #endif //ANDROID_RS_SERIALIZE
- void FontState::init(Context *rsc) {
- mRSC = rsc;
- }
- void FontState::flushAllAndInvalidate() {
- if (mCurrentQuadIndex != 0) {
- issueDrawCommand();
- mCurrentQuadIndex = 0;
- }
- for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
- mActiveFonts[i]->invalidateTextureCache();
- }
- for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
- mCacheLines[i]->mCurrentCol = 0;
- }
- }
- #ifndef ANDROID_RS_SERIALIZE
- bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
- // If the glyph is too tall, don't cache it
- if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
- ALOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
- return false;
- }
- // Now copy the bitmap into the cache texture
- uint32_t startX = 0;
- uint32_t startY = 0;
- bool bitmapFit = false;
- for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
- bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
- if (bitmapFit) {
- break;
- }
- }
- // If the new glyph didn't fit, flush the state so far and invalidate everything
- if (!bitmapFit) {
- flushAllAndInvalidate();
- // Try to fit it again
- for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
- bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
- if (bitmapFit) {
- break;
- }
- }
- // if we still don't fit, something is wrong and we shouldn't draw
- if (!bitmapFit) {
- ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
- return false;
- }
- }
- *retOriginX = startX;
- *retOriginY = startY;
- uint32_t endX = startX + bitmap->width;
- uint32_t endY = startY + bitmap->rows;
- uint32_t cacheWidth = getCacheTextureType()->getDimX();
- uint8_t *cacheBuffer = mCacheBuffer;
- uint8_t *bitmapBuffer = bitmap->buffer;
- uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
- for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
- for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
- uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
- cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
- }
- }
- // This will dirty the texture and the shader so next time
- // we draw it will upload the data
- mRSC->mHal.funcs.allocation.data2D(mRSC, mTextTexture.get(), 0, 0, 0,
- RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, mCacheWidth, mCacheHeight,
- mCacheBuffer, mCacheWidth*mCacheHeight, mCacheWidth);
- mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
- // Some debug code
- /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
- ALOGE("Cache Line: H: %u Empty Space: %f",
- mCacheLines[i]->mMaxHeight,
- (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
- }*/
- return true;
- }
- #endif //ANDROID_RS_SERIALIZE
- void FontState::initRenderState() {
- const char *shaderString = "varying vec2 varTex0;\n"
- "void main() {\n"
- " lowp vec4 col = UNI_Color;\n"
- " col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"
- " col.a = pow(col.a, UNI_Gamma);\n"
- " gl_FragColor = col;\n"
- "}\n";
- const char *textureNames[] = { "Tex0" };
- const size_t textureNamesLengths[] = { 4 };
- size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
- ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
- RS_KIND_USER, false, 4);
- ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
- RS_KIND_USER, false, 1);
- const char *ebn1[] = { "Color", "Gamma" };
- const Element *ebe1[] = {colorElem.get(), gammaElem.get()};
- ObjectBaseRef<const Element> constInput = Element::create(mRSC, 2, ebe1, ebn1);
- ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1);
- uintptr_t tmp[4];
- tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
- tmp[1] = (uintptr_t)inputType.get();
- tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
- tmp[3] = RS_TEXTURE_2D;
- mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
- RS_ALLOCATION_USAGE_SCRIPT |
- RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
- ProgramFragment *pf = new ProgramFragment(mRSC, shaderString, strlen(shaderString),
- textureNames, numTextures, textureNamesLengths,
- tmp, 4);
- mFontShaderF.set(pf);
- mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
- mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
- RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
- RS_SAMPLER_CLAMP).get());
- mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
- mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
- false, false,
- RS_BLEND_SRC_SRC_ALPHA,
- RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
- RS_DEPTH_FUNC_ALWAYS).get());
- mFontProgramStore->init();
- }
- void FontState::initTextTexture() {
- ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
- RS_KIND_PIXEL_A, true, 1);
- // We will allocate a texture to initially hold 32 character bitmaps
- mCacheHeight = 256;
- mCacheWidth = 1024;
- ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), mCacheWidth, mCacheHeight);
- mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
- Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
- RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
- mTextTexture.set(cacheAlloc);
- // Split up our cache texture into lines of certain widths
- int32_t nextLine = 0;
- mCacheLines.push_back(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
- nextLine += mCacheLines.back()->mMaxHeight;
- mCacheLines.push_back(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
- nextLine += mCacheLines.back()->mMaxHeight;
- mCacheLines.push_back(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
- nextLine += mCacheLines.back()->mMaxHeight;
- mCacheLines.push_back(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
- nextLine += mCacheLines.back()->mMaxHeight;
- mCacheLines.push_back(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
- nextLine += mCacheLines.back()->mMaxHeight;
- mCacheLines.push_back(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
- nextLine += mCacheLines.back()->mMaxHeight;
- mCacheLines.push_back(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
- }
- // Avoid having to reallocate memory and render quad by quad
- void FontState::initVertexArrayBuffers() {
- // Now lets write index data
- ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
- ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), mMaxNumberOfQuads * 6);
- Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
- RS_ALLOCATION_USAGE_SCRIPT |
- RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
- uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
- // Four verts, two triangles , six indices per quad
- for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
- int32_t i6 = i * 6;
- int32_t i4 = i * 4;
- indexPtr[i6 + 0] = i4 + 0;
- indexPtr[i6 + 1] = i4 + 1;
- indexPtr[i6 + 2] = i4 + 2;
- indexPtr[i6 + 3] = i4 + 0;
- indexPtr[i6 + 4] = i4 + 2;
- indexPtr[i6 + 5] = i4 + 3;
- }
- indexAlloc->sendDirty(mRSC);
- ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
- ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
- const char *ebn1[] = { "position", "texture0" };
- const Element *ebe1[] = {posElem.get(), texElem.get()};
- ObjectBaseRef<const Element> vertexDataElem = Element::create(mRSC, 2, ebe1, ebn1);
- ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(), mMaxNumberOfQuads * 4);
- Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
- RS_ALLOCATION_USAGE_SCRIPT);
- mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
- mMesh.set(new Mesh(mRSC, 1, 1));
- mMesh->setVertexBuffer(vertexAlloc, 0);
- mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
- mMesh->init();
- mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
- mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
- }
- // We don't want to allocate anything unless we actually draw text
- void FontState::checkInit() {
- if (mInitialized) {
- return;
- }
- initTextTexture();
- initRenderState();
- initVertexArrayBuffers();
- // We store a string with letters in a rough frequency of occurrence
- mLatinPrecache = " eisarntolcdugpmhbyfvkwzxjq"
- "EISARNTOLCDUGPMHBYFVKWZXJQ"
- ",.?!()-+@;:`'0123456789";
- mInitialized = true;
- }
- void FontState::issueDrawCommand() {
- Context::PushState ps(mRSC);
- mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
- mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
- mRSC->setProgramFragment(mFontShaderF.get());
- mRSC->setProgramStore(mFontProgramStore.get());
- if (mConstantsDirty) {
- mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
- mConstantsDirty = false;
- }
- if (!mRSC->setupCheck()) {
- return;
- }
- mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
- }
- void FontState::appendMeshQuad(float x1, float y1, float z1,
- float u1, float v1,
- float x2, float y2, float z2,
- float u2, float v2,
- float x3, float y3, float z3,
- float u3, float v3,
- float x4, float y4, float z4,
- float u4, float v4) {
- const uint32_t vertsPerQuad = 4;
- const uint32_t floatsPerVert = 6;
- float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
- if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
- return;
- }
- /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
- ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
- ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
- ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
- (*currentPos++) = x1;
- (*currentPos++) = y1;
- (*currentPos++) = z1;
- (*currentPos++) = 0;
- (*currentPos++) = u1;
- (*currentPos++) = v1;
- (*currentPos++) = x2;
- (*currentPos++) = y2;
- (*currentPos++) = z2;
- (*currentPos++) = 0;
- (*currentPos++) = u2;
- (*currentPos++) = v2;
- (*currentPos++) = x3;
- (*currentPos++) = y3;
- (*currentPos++) = z3;
- (*currentPos++) = 0;
- (*currentPos++) = u3;
- (*currentPos++) = v3;
- (*currentPos++) = x4;
- (*currentPos++) = y4;
- (*currentPos++) = z4;
- (*currentPos++) = 0;
- (*currentPos++) = u4;
- (*currentPos++) = v4;
- mCurrentQuadIndex ++;
- if (mCurrentQuadIndex == mMaxNumberOfQuads) {
- issueDrawCommand();
- mCurrentQuadIndex = 0;
- }
- }
- uint32_t FontState::getRemainingCacheCapacity() {
- uint32_t remainingCapacity = 0;
- uint32_t totalPixels = 0;
- for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
- remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
- totalPixels += mCacheLines[i]->mMaxWidth;
- }
- remainingCapacity = (remainingCapacity * 100) / totalPixels;
- return remainingCapacity;
- }
- void FontState::precacheLatin(Font *font) {
- // Remaining capacity is measured in %
- uint32_t remainingCapacity = getRemainingCacheCapacity();
- uint32_t precacheIdx = 0;
- const size_t l = strlen(mLatinPrecache);
- while ((remainingCapacity > 25) && (precacheIdx < l)) {
- font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
- remainingCapacity = getRemainingCacheCapacity();
- precacheIdx ++;
- }
- }
- void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
- uint32_t startIndex, int32_t numGlyphs,
- Font::RenderMode mode,
- Font::Rect *bounds,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
- checkInit();
- // Render code here
- Font *currentFont = mRSC->getFont();
- if (!currentFont) {
- if (!mDefault.get()) {
- char fullPath[1024];
- const char * root = getenv("ANDROID_ROOT");
- rsAssert(strlen(root) < 256);
- strlcpy(fullPath, root, sizeof(fullPath));
- strlcat(fullPath, "/fonts/Roboto-Regular.ttf", sizeof(fullPath));
- fullPath[sizeof(fullPath)-1] = '\0';
- mDefault.set(Font::create(mRSC, fullPath, 8, mRSC->getDPI()));
- }
- currentFont = mDefault.get();
- }
- if (!currentFont) {
- ALOGE("Unable to initialize any fonts");
- return;
- }
- // Cull things that are off the screen
- mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
- mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
- currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
- mode, bounds, bitmap, bitmapW, bitmapH);
- if (mCurrentQuadIndex != 0) {
- issueDrawCommand();
- mCurrentQuadIndex = 0;
- }
- }
- void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
- renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
- bounds->bottom = - bounds->bottom;
- bounds->top = - bounds->top;
- }
- void FontState::setFontColor(float r, float g, float b, float a) {
- mConstants.mFontColor[0] = r;
- mConstants.mFontColor[1] = g;
- mConstants.mFontColor[2] = b;
- mConstants.mFontColor[3] = a;
- mConstants.mGamma = 1.0f;
- const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
- if (luminance <= mBlackThreshold) {
- mConstants.mGamma = mBlackGamma;
- } else if (luminance >= mWhiteThreshold) {
- mConstants.mGamma = mWhiteGamma;
- }
- mConstantsDirty = true;
- }
- void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
- *r = mConstants.mFontColor[0];
- *g = mConstants.mFontColor[1];
- *b = mConstants.mFontColor[2];
- *a = mConstants.mFontColor[3];
- }
- void FontState::deinit(Context *rsc) {
- mInitialized = false;
- mFontShaderFConstant.clear();
- mMesh.clear();
- mFontShaderF.clear();
- mFontSampler.clear();
- mFontProgramStore.clear();
- mTextTexture.clear();
- for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
- delete mCacheLines[i];
- }
- mCacheLines.clear();
- mDefault.clear();
- #ifndef ANDROID_RS_SERIALIZE
- if (mLibrary) {
- FT_Done_FreeType( mLibrary );
- mLibrary = nullptr;
- }
- #endif //ANDROID_RS_SERIALIZE
- }
- #ifndef ANDROID_RS_SERIALIZE
- bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
- if ((uint32_t)bitmap->rows > mMaxHeight) {
- return false;
- }
- if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
- *retOriginX = mCurrentCol;
- *retOriginY = mCurrentRow;
- mCurrentCol += bitmap->width;
- mDirty = true;
- return true;
- }
- return false;
- }
- #endif //ANDROID_RS_SERIALIZE
- RsFont rsi_FontCreateFromFile(Context *rsc,
- char const *name, size_t name_length,
- float fontSize, uint32_t dpi) {
- Font *newFont = Font::create(rsc, name, fontSize, dpi);
- if (newFont) {
- newFont->incUserRef();
- }
- return newFont;
- }
- RsFont rsi_FontCreateFromMemory(Context *rsc,
- char const *name, size_t name_length,
- float fontSize, uint32_t dpi,
- const void *data, size_t data_length) {
- Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
- if (newFont) {
- newFont->incUserRef();
- }
- return newFont;
- }
- } // namespace renderscript
- } // namespace android
|