rsFont.cpp revision 94bbccc36322168a596369c8341dad938c8f949f
19b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
29b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk/*
39b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * Copyright (C) 2009 The Android Open Source Project
49b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *
59b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * Licensed under the Apache License, Version 2.0 (the "License");
69b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * you may not use this file except in compliance with the License.
79b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * You may obtain a copy of the License at
89b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *
99b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *      http://www.apache.org/licenses/LICENSE-2.0
109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *
119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * Unless required by applicable law or agreed to in writing, software
129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * distributed under the License is distributed on an "AS IS" BASIS,
139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * See the License for the specific language governing permissions and
159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * limitations under the License.
169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk */
179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#ifndef ANDROID_RS_BUILD_FOR_HOST
199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsContext.h"
209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#else
219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsContextHostStub.h"
229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#endif
239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsFont.h"
259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsProgramFragment.h"
269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include FT_BITMAP_H
279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES/gl.h>
299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES/glext.h>
309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES2/gl2.h>
319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES2/gl2ext.h>
329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukusing namespace android;
349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukusing namespace android::renderscript;
359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
369b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL)
379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
38071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mAllocFile = __FILE__;
39071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mAllocLine = __LINE__;
409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = false;
42b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mFace = NULL;
439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukbool Font::init(const char *name, uint32_t fontSize, uint32_t dpi)
469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mInitialized) {
489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Reinitialization of fonts not supported");
499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 fontsDir("/fonts/");
539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 fullPath(getenv("ANDROID_ROOT"));
549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    fullPath += fontsDir;
559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    fullPath += name;
569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
57071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(error) {
599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Unable to initialize font %s", fullPath.string());
609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontName = name;
649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSize = fontSize;
659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDpi = dpi;
669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(error) {
699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Unable to set font size on %s", fullPath.string());
709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::invalidateTextureCache()
809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y)
879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    int nPenX = x + glyph->mBitmapLeft;
919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    int nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0,
949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            glyph->mBitmapMinU, glyph->mBitmapMaxV,
959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            nPenX + (int)glyph->mBitmapWidth, nPenY, 0,
979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            glyph->mBitmapMaxU, glyph->mBitmapMaxV,
989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            nPenX + (int)glyph->mBitmapWidth, nPenY - (int)glyph->mBitmapHeight, 0,
1009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            glyph->mBitmapMaxU, glyph->mBitmapMinV,
1019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            nPenX, nPenY - (int)glyph->mBitmapHeight, 0,
1039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            glyph->mBitmapMinU, glyph->mBitmapMinV);
1049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
1059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y)
1079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
1089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
1099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
1109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    int penX = x, penY = y;
1139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    int glyphsLeft = 1;
1149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(numGlyphs > 0) {
1159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        glyphsLeft = numGlyphs;
1169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t index = start;
1199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t nextIndex = 0;
1209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    while (glyphsLeft > 0) {
1229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        int32_t utfChar = utf32_at(text, len, index, &nextIndex);
1249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Reached the end of the string or encountered
1269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(utfChar < 0) {
1279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
1289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Move to the next character in the array
1319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        index = nextIndex;
1329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
13394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
1349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
1369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(cachedGlyph->mIsValid) {
1379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            drawCachedGlyph(cachedGlyph, penX, penY);
1389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        penX += (cachedGlyph->mAdvance.x >> 6);
1419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
1439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(numGlyphs > 0) {
1449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            glyphsLeft --;
1459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
1489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
14994bbccc36322168a596369c8341dad938c8f949fAlex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
15094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
15194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
15294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    if(cachedGlyph == NULL) {
15394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
15494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
15594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Is the glyph still in texture cache?
15694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    if(!cachedGlyph->mIsValid) {
15794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        updateGlyphCache(cachedGlyph);
15894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
15994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
16094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return cachedGlyph;
16194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
16294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
1639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph)
1649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
165071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
166071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(error) {
167071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        LOGE("Couldn't load glyph.");
168071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        return;
169071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
1709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
171071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mAdvance = mFace->glyph->advance;
172071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
173071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
1749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
175071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
1769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
1789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
1799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
1809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
1829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
183071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
1849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!glyph->mIsValid) {
1869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
1879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
189071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
190071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
1919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinX = startX;
1939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinY = startY;
194071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
195071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
1969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
1989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
1999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
2019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
2029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
2039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
2049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2069b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
2079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
2099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
2109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
2129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mIsValid = false;
2139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    updateGlyphCache(newGlyph);
2159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return newGlyph;
2179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2199b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
2209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
2229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < activeFonts.size(); i ++) {
2249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        Font *ithFont = activeFonts[i];
2259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
2269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return ithFont;
2279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *newFont = new Font(rsc);
2319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi);
2329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(isInitialized) {
2339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        activeFonts.push(newFont);
23494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
2359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return newFont;
2369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    delete newFont;
2399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return NULL;
2409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2439b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::~Font()
2449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mFace) {
2469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        FT_Done_Face(mFace);
2479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
2509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
2519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            mRSC->mStateFont.mActiveFonts.removeAt(ct);
2529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
2539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
2579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
2589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete glyph;
2599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2629b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFontState::FontState()
2639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
2659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
2669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex = 0;
2679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC = NULL;
268b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mLibrary = NULL;
26955e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
2709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2729b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFontState::~FontState()
2739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
2759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete mCacheLines[i];
2769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
2799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
281071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex SakhartchoukFT_Library FontState::getLib()
2829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!mLibrary) {
284071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
2859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(error) {
2869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Unable to initialize freetype");
287071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            return NULL;
2889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
290b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
291071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return mLibrary;
292071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk}
2939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
294071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchoukvoid FontState::init(Context *rsc)
295071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk{
296071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mRSC = rsc;
2979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::flushAllAndInvalidate()
3009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
3029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
3039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
3049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
3069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
3079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
3099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
3109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
3149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the glyph is too tall, don't cache it
3169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
3179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
3189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
3199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
3229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
3239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
3249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool bitmapFit = false;
3269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
3279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
3289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(bitmapFit) {
3299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
3309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
3349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!bitmapFit) {
3359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        flushAllAndInvalidate();
3369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Try to fit it again
3389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
3399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
3409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            if(bitmapFit) {
3419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                break;
3429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            }
3439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
3469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(!bitmapFit) {
3479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
3489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return false;
3499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginX = startX;
3539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginY = startY;
3549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
3569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
3579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
3599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
3619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    unsigned char *bitmapBuffer = bitmap->buffer;
3629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
3649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
3659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
3669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
3679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
3689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // This will dirty the texture and the shader so next time
3729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // we draw it will upload the data
3739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
3749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontShaderF->bindTexture(0, mTextTexture.get());
3759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Some debug code
3779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
3789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Cache Line: H: %u Empty Space: %f",
3799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
3809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
3819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }*/
3839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
3859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initRenderState()
3889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
389442a647424e6537e94341654e3ae5d52efd84862Jason Sams    uint32_t tmp[] = {
3909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        RS_TEX_ENV_MODE_REPLACE, 1,
3919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        RS_TEX_ENV_MODE_NONE, 0,
392442a647424e6537e94341654e3ae5d52efd84862Jason Sams        0, 0
3939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    };
394442a647424e6537e94341654e3ae5d52efd84862Jason Sams    ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 6);
3959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontShaderF.set(pf);
3969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontShaderF->init(mRSC);
3979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
3999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                      RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
4009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSampler.set(sampler);
4019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontShaderF->bindSampler(0, sampler);
4029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ProgramStore *fontStore = new ProgramStore(mRSC);
4049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore.set(fontStore);
4059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
4069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
4079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDitherEnable(false);
4089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthMask(false);
4099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initTextTexture()
4129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
4139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
4149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
4169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *texType = new Type(mRSC);
4179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setElement(alphaElem);
4189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setDimX(1024);
4199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setDimY(256);
4209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->compute();
4219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *cacheAlloc = new Allocation(mRSC, texType);
4239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
4249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
4259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
4279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    int nextLine = 0;
4289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
4299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
4309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
4319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
43294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
43394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
4349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
4359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
4369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
4379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
4389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
4399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
4409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
4419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
4449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initVertexArrayBuffers()
4459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
4469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now lets write index data
4479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
4489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *indexType = new Type(mRSC);
4499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
4509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->setDimX(numIndicies);
4519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->setElement(indexElem);
4529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->compute();
4539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *indexAlloc = new Allocation(mRSC, indexType);
4559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
4569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
4589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
4599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        int i6 = i * 6;
4609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        int i4 = i * 4;
4619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
4639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
4649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
4659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
4679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
4689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
4699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexAlloc->deferedUploadToBufferObject(mRSC);
4729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer.set(indexAlloc);
4739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
4759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
4769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *elemArray[2];
4789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    elemArray[0] = posElem;
4799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    elemArray[1] = texElem;
4809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 posName("position");
4829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 texName("texture0");
4839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const char *nameArray[2];
4859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nameArray[0] = posName.string();
4869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nameArray[1] = texName.string();
4879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t lengths[2];
4889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    lengths[0] = posName.size();
4899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    lengths[1] = texName.size();
4909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths);
4929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *vertexDataType = new Type(mRSC);
4949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->setDimX(mMaxNumberOfQuads * 4);
4959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->setElement(vertexDataElem);
4969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->compute();
4979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
4999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
5009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mVertexArray.set(vertexAlloc);
5029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
5059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::checkInit()
5069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
5079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mInitialized) {
5089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
5099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
5109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initTextTexture();
5129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initRenderState();
5139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initVertexArrayBuffers();
5159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
5179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::issueDrawCommand() {
5209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
5229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setVertex(mRSC->getDefaultProgramVertex());
5239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
52480a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
52580a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    mRSC->setRaster(mRSC->getDefaultProgramRaster());
52680a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk
5279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
5289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragment(mFontShaderF.get());
5299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
5319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragmentStore(mFontProgramStore.get());
5329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
53355e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    if(mFontColorDirty) {
53455e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk        mFontShaderF->setConstantColor(mFontColor[0], mFontColor[1], mFontColor[2], mFontColor[3]);
53555e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk        mFontColorDirty = false;
53655e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    }
53755e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
5389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if (!mRSC->setupCheck()) {
5399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setVertex((ProgramVertex *)tmpV.get());
54080a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk        mRSC->setRaster((ProgramRaster *)tmpR.get());
5419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setFragment((ProgramFragment *)tmpF.get());
5429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
5439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
5449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
5459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *vtx = (float*)mVertexArray->getPtr();
5479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *tex = vtx + 3;
5489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    VertexArray va;
5509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
5519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
5529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
5539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer->uploadCheck(mRSC);
5559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
5569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
5579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Reset the state
5599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setVertex((ProgramVertex *)tmpV.get());
56080a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    mRSC->setRaster((ProgramRaster *)tmpR.get());
5619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragment((ProgramFragment *)tmpF.get());
5629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
5639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
5669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u1, float v1,
5679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x2, float y2, float z2,
5689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u2, float v2,
5699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x3, float y3, float z3,
5709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u3, float v3,
5719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x4, float y4, float z4,
5729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u4, float v4)
5739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
5749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
5759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t floatsPerVert = 5;
5769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
5779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Cull things that are off the screen
5799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float width = (float)mRSC->getWidth();
5809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float height = (float)mRSC->getHeight();
5819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
5839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
5849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
5859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
5879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
5889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
5899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
5909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x1;
5929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y1;
5939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z1;
5949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u1;
5959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v1;
5969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x2;
5989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y2;
5999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z2;
6009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u2;
6019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v2;
6029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x3;
6049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y3;
6059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z3;
6069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u3;
6079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v3;
6089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x4;
6109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y4;
6119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z4;
6129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u4;
6139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v4;
6149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex ++;
6169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex == mMaxNumberOfQuads) {
6189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
6199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
6209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
62394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
62494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = 0;
62594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    float totalPixels = 0;
62694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
62794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
62894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
62994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
63094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
63194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return remainingCapacity;
63294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
63394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
63494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
63594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Remaining capacity is measured in %
63694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
63794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t precacheIdx = 0;
63894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
63994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
64094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
64194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        precacheIdx ++;
64294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
64394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
64494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
64594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
6469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
6479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
6489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    checkInit();
6499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Render code here
6519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
652071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(!currentFont) {
653071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        if(!mDefault.get()) {
654071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
655071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        }
656071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        currentFont = mDefault.get();
657071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
658b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    if(!currentFont) {
659b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        LOGE("Unable to initialize any fonts");
660b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        return;
661b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
662b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
6639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
6649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
6669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
6679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
6689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
66994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
67094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
67194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
67294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
67394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
67494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    mLatinPrecache += String8("0123456789");
6759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(const char *text, int x, int y)
6789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
6799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t textLen = strlen(text);
6809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    renderText(text, textLen, 0, -1, x, y);
6819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(Allocation *alloc, int x, int y)
6849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
6859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!alloc) {
6869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const char *text = (const char *)alloc->getPtr();
6909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t allocSize = alloc->getType()->getSizeBytes();
6919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    renderText(text, allocSize, 0, -1, x, y);
6929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
6959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
6969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!alloc) {
6979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const char *text = (const char *)alloc->getPtr();
7019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t allocSize = alloc->getType()->getSizeBytes();
7029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    renderText(text, allocSize, start, len, x, y);
7039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
705fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
706fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk    mFontColor[0] = r;
707fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk    mFontColor[1] = g;
708fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk    mFontColor[2] = b;
709fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk    mFontColor[3] = a;
710fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk    mFontColorDirty = true;
711fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk}
712fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk
71355e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
71455e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    *r = mFontColor[0];
71555e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    *g = mFontColor[1];
71655e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    *b = mFontColor[2];
71755e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    *a = mFontColor[3];
71855e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk}
71955e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
7209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::deinit(Context *rsc)
7219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
722071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mInitialized = false;
723071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
724071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mIndexBuffer.clear();
725071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mVertexArray.clear();
726071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
727071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontShaderF.clear();
728071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontSampler.clear();
729071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontProgramStore.clear();
730071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
731071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mTextTexture.clear();
732071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
733071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        delete mCacheLines[i];
7349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
735071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mCacheLines.clear();
7369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDefault.clear();
738071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
739b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    Vector<Font*> fontsToDereference = mActiveFonts;
740b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
741b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        fontsToDereference[i]->zeroUserRef();
742b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
743b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
744071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(mLibrary) {
745071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Done_FreeType( mLibrary );
746b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        mLibrary = NULL;
747071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
7489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace android {
7519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace renderscript {
7529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7539b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
7549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
755071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
756071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(newFont) {
757071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        newFont->incUserRef();
758071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
759071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return newFont;
7609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // renderscript
7639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // android
764