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