rsFont.cpp revision c9fa30536fb41f0166153561388b7c42f7cb85a0
1d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
2d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk/*
3d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Copyright (C) 2009 The Android Open Source Project
4d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
5d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Licensed under the Apache License, Version 2.0 (the "License");
6d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * you may not use this file except in compliance with the License.
7d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * You may obtain a copy of the License at
8d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
9d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *      http://www.apache.org/licenses/LICENSE-2.0
10d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
11d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Unless required by applicable law or agreed to in writing, software
12d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * distributed under the License is distributed on an "AS IS" BASIS,
13d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * See the License for the specific language governing permissions and
15d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * limitations under the License.
16d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk */
17d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
18d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#ifndef ANDROID_RS_BUILD_FOR_HOST
19d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsContext.h"
20d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#else
21d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsContextHostStub.h"
22d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#endif
23d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
24d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsFont.h"
25d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsProgramFragment.h"
26c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk#include <cutils/properties.h>
27d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include FT_BITMAP_H
28d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
29d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES/gl.h>
30d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES/glext.h>
31d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES2/gl2.h>
32d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES2/gl2ext.h>
33d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
34d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android;
35d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android::renderscript;
36d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
37d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL)
38d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
39a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mAllocFile = __FILE__;
40a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mAllocLine = __LINE__;
41d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
42d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = false;
433659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mFace = NULL;
44d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
45d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
46d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukbool Font::init(const char *name, uint32_t fontSize, uint32_t dpi)
47d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
48d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mInitialized) {
49d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Reinitialization of fonts not supported");
50d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
51d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
52d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
53d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    String8 fontsDir("/fonts/");
54d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    String8 fullPath(getenv("ANDROID_ROOT"));
55d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    fullPath += fontsDir;
56d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    fullPath += name;
57d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
58a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
59d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(error) {
60d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Unable to initialize font %s", fullPath.string());
61d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
62d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
63d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
64d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontName = name;
65d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSize = fontSize;
66d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDpi = dpi;
67d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
68d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
69d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(error) {
70d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Unable to set font size on %s", fullPath.string());
71d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
72d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
73d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
74d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
75d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
76d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
77d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
78d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
79d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
80d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid Font::invalidateTextureCache()
81d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
82d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
83d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
84d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
85d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
86d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
87d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y)
88d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
89d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
90d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
91d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    int nPenX = x + glyph->mBitmapLeft;
92d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    int nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
93d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
94d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0,
95d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            glyph->mBitmapMinU, glyph->mBitmapMaxV,
96d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
97d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            nPenX + (int)glyph->mBitmapWidth, nPenY, 0,
98d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            glyph->mBitmapMaxU, glyph->mBitmapMaxV,
99d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
100d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            nPenX + (int)glyph->mBitmapWidth, nPenY - (int)glyph->mBitmapHeight, 0,
101d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            glyph->mBitmapMaxU, glyph->mBitmapMinV,
102d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
103d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            nPenX, nPenY - (int)glyph->mBitmapHeight, 0,
104d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            glyph->mBitmapMinU, glyph->mBitmapMinV);
105d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
106d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
107d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y)
108d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
109d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
110d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
111d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
112d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
113d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    int penX = x, penY = y;
114d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    int glyphsLeft = 1;
115d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(numGlyphs > 0) {
116d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        glyphsLeft = numGlyphs;
117d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
118d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
119d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t index = start;
120d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t nextIndex = 0;
121d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
122d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    while (glyphsLeft > 0) {
123d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
124d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        int32_t utfChar = utf32_at(text, len, index, &nextIndex);
125d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
126d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Reached the end of the string or encountered
127d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(utfChar < 0) {
128d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
129d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
130d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
131d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Move to the next character in the array
132d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        index = nextIndex;
133d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
13401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
135d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
136d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
137d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(cachedGlyph->mIsValid) {
138d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            drawCachedGlyph(cachedGlyph, penX, penY);
139d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
140d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
141d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        penX += (cachedGlyph->mAdvance.x >> 6);
142d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
143d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
144d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(numGlyphs > 0) {
145d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            glyphsLeft --;
146d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
147d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
148d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
149d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
15001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
15101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
15201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
15301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    if(cachedGlyph == NULL) {
15401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
15501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
15601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Is the glyph still in texture cache?
15701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    if(!cachedGlyph->mIsValid) {
15801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        updateGlyphCache(cachedGlyph);
15901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
16001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
16101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return cachedGlyph;
16201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
16301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
164d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph)
165d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
166a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
167a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    if(error) {
168a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        LOGE("Couldn't load glyph.");
169a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        return;
170a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
171d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
172a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mAdvance = mFace->glyph->advance;
173a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
174a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
175d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
176a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
177d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
178d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
179d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
180d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
181d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
182d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
183d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
184a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
185d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
186d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!glyph->mIsValid) {
187d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
188d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
189d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
190a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endX = startX + bitmap->width;
191a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
192d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
193d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinX = startX;
194d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinY = startY;
195a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
196a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
197d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
198d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
199d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
200d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
201d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
202d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
203d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
204d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
205d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
206d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
207d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
208d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
209d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
210d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
211d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
212d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
213d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mIsValid = false;
214d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
215d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    updateGlyphCache(newGlyph);
216d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
217d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return newGlyph;
218d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
219d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
220d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
221d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
22235b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    rsc->mStateFont.checkInit();
223d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
224d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
225d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < activeFonts.size(); i ++) {
226d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        Font *ithFont = activeFonts[i];
227d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
228d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return ithFont;
229d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
230d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
231d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
232d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *newFont = new Font(rsc);
233d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi);
234d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(isInitialized) {
235d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        activeFonts.push(newFont);
23601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
237d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return newFont;
238d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
239d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
240d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    delete newFont;
241d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return NULL;
242d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
243d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
244d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
245d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFont::~Font()
246d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
247d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mFace) {
248d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        FT_Done_Face(mFace);
249d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
250d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
251d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
252d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
253d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            mRSC->mStateFont.mActiveFonts.removeAt(ct);
254d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
255d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
256d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
257d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
258d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
259d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
260d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete glyph;
261d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
262d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
263d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
264d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFontState::FontState()
265d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
266d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
267d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
268d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex = 0;
269d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC = NULL;
2703659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mLibrary = NULL;
271ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
272c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
273c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the renderer properties
274c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    char property[PROPERTY_VALUE_MAX];
275c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
276c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the gamma
277c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    float gamma = DEFAULT_TEXT_GAMMA;
278c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
279c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Setting text gamma to %s", property);
280c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        gamma = atof(property);
281c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else {
282c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
283c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
284c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
285c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the black gamma threshold
286c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    int blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
287c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
288c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Setting text black gamma threshold to %s", property);
289c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        blackThreshold = atoi(property);
290c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else {
291c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Using default text black gamma threshold of %d",
292c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk                DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
293c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
294c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mBlackThreshold = (float)(blackThreshold) / 255.0f;
295c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
296c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the white gamma threshold
297c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    int whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
298c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
299c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Setting text white gamma threshold to %s", property);
300c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        whiteThreshold = atoi(property);
301c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else {
302c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Using default white black gamma threshold of %d",
303c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk                DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
304c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
305c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
306c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
307c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Compute the gamma tables
308c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mBlackGamma = gamma;
309c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteGamma = 1.0f / gamma;
310d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
311d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
312d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFontState::~FontState()
313d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
314d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
315d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete mCacheLines[i];
316d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
317d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
318d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
319d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
320d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
321a1ccecd965c07c2739f1258989526051a010bdabAlex SakhartchoukFT_Library FontState::getLib()
322d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
323d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!mLibrary) {
324a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
325d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(error) {
326d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            LOGE("Unable to initialize freetype");
327a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk            return NULL;
328d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
329d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
3303659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
331a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return mLibrary;
332a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk}
333d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
334a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchoukvoid FontState::init(Context *rsc)
335a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk{
336a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mRSC = rsc;
337d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
338d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
339d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::flushAllAndInvalidate()
340d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
341d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
342d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
343d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
344d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
345d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
346d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
347d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
348d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
349d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
350d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
351d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
352d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
353d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
354d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
355d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the glyph is too tall, don't cache it
356d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
357d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
358d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
359d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
360d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
361d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
362d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
363d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
364d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
365d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    bool bitmapFit = false;
366d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
367d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
368d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(bitmapFit) {
369d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
370d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
371d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
372d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
373d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
374d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!bitmapFit) {
375d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        flushAllAndInvalidate();
376d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
377d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Try to fit it again
378d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
379d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
380d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            if(bitmapFit) {
381d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                break;
382d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            }
383d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
384d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
385d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
386d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(!bitmapFit) {
387d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
388d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return false;
389d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
390d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
391d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
392d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginX = startX;
393d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginY = startY;
394d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
395d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
396d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
397d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
398d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
399d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
400d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
401d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    unsigned char *bitmapBuffer = bitmap->buffer;
402d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
403d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
404d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
405d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
406d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
407d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
408d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
409d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
410d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
411d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // This will dirty the texture and the shader so next time
412d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // we draw it will upload the data
413d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
414383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
415d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
416d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Some debug code
417d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
418d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Cache Line: H: %u Empty Space: %f",
419d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
420d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
421d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
422d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }*/
423d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
424d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
425d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
426d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
427d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::initRenderState()
428d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
429e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    String8 shaderString("varying vec4 varTex0;\n");
430e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("void main() {\n");
431e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
432e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
433c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
434e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
435e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("}\n");
436e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
437e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
438c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
439e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
440e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
441c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
442e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
443e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
444e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    Type *inputType = new Type(mRSC);
445e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    inputType->setElement(constInput);
446e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    inputType->setDimX(1);
447e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    inputType->compute();
448e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
449e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    uint32_t tmp[4];
450e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
451e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[1] = (uint32_t)inputType;
452e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
453e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[3] = 1;
454e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
455e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mFontShaderFConstant.set(new Allocation(mRSC, inputType));
456e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
457e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk                                              shaderString.length(), tmp, 4);
458d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontShaderF.set(pf);
459383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
460d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
461d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
462d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                      RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
463d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSampler.set(sampler);
464383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, sampler);
465d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
466d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    ProgramStore *fontStore = new ProgramStore(mRSC);
467d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore.set(fontStore);
468d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
469d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
470d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setDitherEnable(false);
471d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setDepthMask(false);
472d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
473d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
474d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::initTextTexture()
475d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
476d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
477d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
478d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
479d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Type *texType = new Type(mRSC);
480d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    texType->setElement(alphaElem);
481d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    texType->setDimX(1024);
482d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    texType->setDimY(256);
483d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    texType->compute();
484d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
485d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Allocation *cacheAlloc = new Allocation(mRSC, texType);
486d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
487d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
488d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
489d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
490d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    int nextLine = 0;
491d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
492d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
493d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
494d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
49501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
49601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
497d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
498d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
499d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
500d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
501d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
502d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
503d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
504d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
505d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
506d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
507d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::initVertexArrayBuffers()
508d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
509d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now lets write index data
510d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
511d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Type *indexType = new Type(mRSC);
512d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
513d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    indexType->setDimX(numIndicies);
514d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    indexType->setElement(indexElem);
515d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    indexType->compute();
516d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
517d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Allocation *indexAlloc = new Allocation(mRSC, indexType);
518d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
519d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
520d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
521d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
522d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        int i6 = i * 6;
523d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        int i4 = i * 4;
524d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
525d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
526d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
527d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
528d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
529d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
530d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
531d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
532d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
533d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
534d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    indexAlloc->deferedUploadToBufferObject(mRSC);
535d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mIndexBuffer.set(indexAlloc);
536d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
537d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
538d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
539d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
540d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *elemArray[2];
541d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    elemArray[0] = posElem;
542d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    elemArray[1] = texElem;
543d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
544d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    String8 posName("position");
545d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    String8 texName("texture0");
546d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
547d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const char *nameArray[2];
548d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nameArray[0] = posName.string();
549d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nameArray[1] = texName.string();
550d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t lengths[2];
551d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    lengths[0] = posName.size();
552d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    lengths[1] = texName.size();
55346e45548dc80e801139c9ccc2f2aa927e7f35027Jason Sams    uint32_t arraySizes[2] = {1, 1};
554d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
55546e45548dc80e801139c9ccc2f2aa927e7f35027Jason Sams    const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
556d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
557d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Type *vertexDataType = new Type(mRSC);
558d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    vertexDataType->setDimX(mMaxNumberOfQuads * 4);
559d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    vertexDataType->setElement(vertexDataElem);
560d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    vertexDataType->compute();
561d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
562d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
563d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
564d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
565d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mVertexArray.set(vertexAlloc);
566d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
567d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
568d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
569d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::checkInit()
570d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
571d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mInitialized) {
572d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
573d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
574d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
575d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initTextTexture();
576d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initRenderState();
577d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
578d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initVertexArrayBuffers();
579d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
58035b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
58135b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
58235b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
58335b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
58435b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("0123456789");
58535b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk
586d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
587d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
588d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
589d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::issueDrawCommand() {
590d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
591d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
592d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setVertex(mRSC->getDefaultProgramVertex());
593d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
594d18c744a37441311c9b65254a35db456835adad3Alex Sakhartchouk    ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
595d18c744a37441311c9b65254a35db456835adad3Alex Sakhartchouk    mRSC->setRaster(mRSC->getDefaultProgramRaster());
596d18c744a37441311c9b65254a35db456835adad3Alex Sakhartchouk
597d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
598d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setFragment(mFontShaderF.get());
599d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
600d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
601d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setFragmentStore(mFontProgramStore.get());
602d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
603c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if(mConstantsDirty) {
604c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
605c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstantsDirty = false;
606ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    }
607ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
608d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if (!mRSC->setupCheck()) {
609d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mRSC->setVertex((ProgramVertex *)tmpV.get());
610d18c744a37441311c9b65254a35db456835adad3Alex Sakhartchouk        mRSC->setRaster((ProgramRaster *)tmpR.get());
611d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mRSC->setFragment((ProgramFragment *)tmpF.get());
612d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
613d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
614d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
615d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
616d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *vtx = (float*)mVertexArray->getPtr();
617d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *tex = vtx + 3;
618d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
619d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    VertexArray va;
620886f11ade9dde05485cb11c0d67d87f76a428f6cAlex Sakhartchouk    va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
621886f11ade9dde05485cb11c0d67d87f76a428f6cAlex Sakhartchouk    va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
622d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
623d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
624d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mIndexBuffer->uploadCheck(mRSC);
625d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
626d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
627d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
628d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Reset the state
629d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setVertex((ProgramVertex *)tmpV.get());
630d18c744a37441311c9b65254a35db456835adad3Alex Sakhartchouk    mRSC->setRaster((ProgramRaster *)tmpR.get());
631d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setFragment((ProgramFragment *)tmpF.get());
632d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
633d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
634d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
635d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
636d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float u1, float v1,
637d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float x2, float y2, float z2,
638d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float u2, float v2,
639d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float x3, float y3, float z3,
640d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float u3, float v3,
641d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float x4, float y4, float z4,
642d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float u4, float v4)
643d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
644d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
645d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t floatsPerVert = 5;
646d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
647d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
648d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Cull things that are off the screen
649d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float width = (float)mRSC->getWidth();
650d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float height = (float)mRSC->getHeight();
651d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
652d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
653d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
654d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
655d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
656d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
657d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
658d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
659d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
660d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
661d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x1;
662d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y1;
663d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z1;
664d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u1;
665d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v1;
666d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
667d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x2;
668d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y2;
669d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z2;
670d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u2;
671d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v2;
672d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
673d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x3;
674d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y3;
675d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z3;
676d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u3;
677d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v3;
678d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
679d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x4;
680d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y4;
681d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z4;
682d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u4;
683d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v4;
684d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
685d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex ++;
686d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
687d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mCurrentQuadIndex == mMaxNumberOfQuads) {
688d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
689d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
690d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
691d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
692d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
69301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
69401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = 0;
69535b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    uint32_t totalPixels = 0;
69601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
69701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
69801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
69901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
70001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
70101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return remainingCapacity;
70201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
70301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
70401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
70501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Remaining capacity is measured in %
70601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
70701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t precacheIdx = 0;
70801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
70901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
71001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
71101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        precacheIdx ++;
71201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
71301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
71401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
71501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
716d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
717d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
718d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    checkInit();
719d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
720d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Render code here
721d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
722a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    if(!currentFont) {
723a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        if(!mDefault.get()) {
724a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk            mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
725a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        }
726a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        currentFont = mDefault.get();
727a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
7283659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    if(!currentFont) {
7293659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        LOGE("Unable to initialize any fonts");
7303659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        return;
7313659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    }
7323659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
733d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
734d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
735d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
736d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
737d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
738d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
739d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
740d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
741d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::renderText(const char *text, int x, int y)
742d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
743d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t textLen = strlen(text);
744d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    renderText(text, textLen, 0, -1, x, y);
745d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
746d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
747d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::renderText(Allocation *alloc, int x, int y)
748d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
749d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!alloc) {
750d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
751d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
752d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
753d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const char *text = (const char *)alloc->getPtr();
754d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t allocSize = alloc->getType()->getSizeBytes();
755d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    renderText(text, allocSize, 0, -1, x, y);
756d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
757d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
758d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
759d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
760d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!alloc) {
761d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
762d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
763d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
764d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const char *text = (const char *)alloc->getPtr();
765d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t allocSize = alloc->getType()->getSizeBytes();
766d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    renderText(text, allocSize, start, len, x, y);
767d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
768d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
7699fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
770c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[0] = r;
771c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[1] = g;
772c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[2] = b;
773c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[3] = a;
774c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
775c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mGamma = 1.0f;
776c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    const int luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
777c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (luminance <= mBlackThreshold) {
778c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mBlackGamma;
779c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
780c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
781c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
782c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstantsDirty = true;
7839fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk}
7849fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk
785ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
786c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *r = mConstants.mFontColor[0];
787c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *g = mConstants.mFontColor[1];
788c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *b = mConstants.mFontColor[2];
789c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *a = mConstants.mFontColor[3];
790ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk}
791ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
792d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::deinit(Context *rsc)
793d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
794a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mInitialized = false;
795a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
79601b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines    mFontShaderFConstant.clear();
79701b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines
798a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mIndexBuffer.clear();
799a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mVertexArray.clear();
800a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
801a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontShaderF.clear();
802a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontSampler.clear();
803a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontProgramStore.clear();
804a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
805a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mTextTexture.clear();
806a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
807a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        delete mCacheLines[i];
808d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
809a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mCacheLines.clear();
810d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
811d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDefault.clear();
812a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
8133659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    Vector<Font*> fontsToDereference = mActiveFonts;
8143659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
8153659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        fontsToDereference[i]->zeroUserRef();
8163659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    }
8173659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
818a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    if(mLibrary) {
819a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Done_FreeType( mLibrary );
8203659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        mLibrary = NULL;
821a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
822d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
823d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
824d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace android {
825d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace renderscript {
826d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
827d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
828d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
829a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
830a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    if(newFont) {
831a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        newFont->incUserRef();
832a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
833a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return newFont;
834d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
835d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
836d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // renderscript
837d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // android
838