rsFont.cpp revision 01f0ad7c13b8878c2167bff10ea875d7509edca5
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{ 22127f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk rsc->mStateFont.checkInit(); 2229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts; 2239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 2249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk for(uint32_t i = 0; i < activeFonts.size(); i ++) { 2259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk Font *ithFont = activeFonts[i]; 2269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) { 2279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk return ithFont; 2289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 2299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 2309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 2319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk Font *newFont = new Font(rsc); 2329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk bool isInitialized = newFont->init(name, fontSize, dpi); 2339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(isInitialized) { 2349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk activeFonts.push(newFont); 23594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk rsc->mStateFont.precacheLatin(newFont); 2369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk return newFont; 2379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 2389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 2399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk delete newFont; 2409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk return NULL; 2419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 2429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 2439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 2449b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::~Font() 2459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 2469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(mFace) { 2479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk FT_Done_Face(mFace); 2489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 2499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 2509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) { 2519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if (mRSC->mStateFont.mActiveFonts[ct] == this) { 2529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mRSC->mStateFont.mActiveFonts.removeAt(ct); 2539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk break; 2549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 2559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 2569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 2579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { 2589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i); 2599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk delete glyph; 2609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 2619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 2629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 2639b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFontState::FontState() 2649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 2659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mInitialized = false; 2669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mMaxNumberOfQuads = 1024; 2679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCurrentQuadIndex = 0; 2689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mRSC = NULL; 269b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk mLibrary = NULL; 27055e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk setFontColor(0.1f, 0.1f, 0.1f, 1.0f); 2719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 2729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 2739b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFontState::~FontState() 2749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 2759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 2769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk delete mCacheLines[i]; 2779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 2789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 2799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk rsAssert(!mActiveFonts.size()); 2809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 2819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 282071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex SakhartchoukFT_Library FontState::getLib() 2839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 2849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(!mLibrary) { 285071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk FT_Error error = FT_Init_FreeType(&mLibrary); 2869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(error) { 2879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk LOGE("Unable to initialize freetype"); 288071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk return NULL; 2899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 2909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 291b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk 292071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk return mLibrary; 293071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk} 2949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 295071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchoukvoid FontState::init(Context *rsc) 296071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk{ 297071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk mRSC = rsc; 2989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 2999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::flushAllAndInvalidate() 3019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 3029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(mCurrentQuadIndex != 0) { 3039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk issueDrawCommand(); 3049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCurrentQuadIndex = 0; 3059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk for(uint32_t i = 0; i < mActiveFonts.size(); i ++) { 3079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mActiveFonts[i]->invalidateTextureCache(); 3089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 3109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCacheLines[i]->mCurrentCol = 0; 3119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 3139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) 3159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 3169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // If the glyph is too tall, don't cache it 3179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) { 3189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); 3199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk return false; 3209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // Now copy the bitmap into the cache texture 3239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk uint32_t startX = 0; 3249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk uint32_t startY = 0; 3259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk bool bitmapFit = false; 3279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 3289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); 3299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(bitmapFit) { 3309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk break; 3319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // If the new glyph didn't fit, flush the state so far and invalidate everything 3359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(!bitmapFit) { 3369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk flushAllAndInvalidate(); 3379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // Try to fit it again 3399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 3409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); 3419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(bitmapFit) { 3429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk break; 3439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // if we still don't fit, something is wrong and we shouldn't draw 3479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(!bitmapFit) { 3489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); 3499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk return false; 3509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *retOriginX = startX; 3549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *retOriginY = startY; 3559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk uint32_t endX = startX + bitmap->width; 3579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk uint32_t endY = startY + bitmap->rows; 3589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk uint32_t cacheWidth = getCacheTextureType()->getDimX(); 3609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr(); 3629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk unsigned char *bitmapBuffer = bitmap->buffer; 3639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 3659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) { 3669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) { 3679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX]; 3689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol; 3699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 3719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // This will dirty the texture and the shader so next time 3739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // we draw it will upload the data 3749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mTextTexture->deferedUploadToTexture(mRSC, false, 0); 375b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get()); 3769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // Some debug code 3789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 3799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk LOGE("Cache Line: H: %u Empty Space: %f", 3809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCacheLines[i]->mMaxHeight, 3819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f); 3829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk }*/ 3849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk return true; 3869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 3879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 3889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initRenderState() 3899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 390c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk String8 shaderString("varying vec4 varTex0;\n"); 391c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk shaderString.append("void main() {\n"); 392c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk shaderString.append(" lowp vec4 col = UNI_Color;\n"); 393c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"); 394c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk shaderString.append(" gl_FragColor = col;\n"); 395c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk shaderString.append("}\n"); 396c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk 397c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4); 398c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk mRSC->mStateElement.elementBuilderBegin(); 399c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1); 400c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC); 401c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk 402c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk Type *inputType = new Type(mRSC); 403c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk inputType->setElement(constInput); 404c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk inputType->setDimX(1); 405c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk inputType->compute(); 406c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk 407c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk uint32_t tmp[4]; 408c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk tmp[0] = RS_PROGRAM_PARAM_CONSTANT; 409c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk tmp[1] = (uint32_t)inputType; 410c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT; 411c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk tmp[3] = 1; 412c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk 413c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk mFontShaderFConstant.set(new Allocation(mRSC, inputType)); 414c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), 415c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk shaderString.length(), tmp, 4); 4169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mFontShaderF.set(pf); 417b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0); 4189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST, 4209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP); 4219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mFontSampler.set(sampler); 422b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk mFontShaderF->bindSampler(mRSC, 0, sampler); 4239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk ProgramStore *fontStore = new ProgramStore(mRSC); 4259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mFontProgramStore.set(fontStore); 4269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS); 4279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA); 4289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mFontProgramStore->setDitherEnable(false); 4299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mFontProgramStore->setDepthMask(false); 4309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 4319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initTextTexture() 4339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 4349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1); 4359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // We will allocate a texture to initially hold 32 character bitmaps 4379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk Type *texType = new Type(mRSC); 4389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk texType->setElement(alphaElem); 4399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk texType->setDimX(1024); 4409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk texType->setDimY(256); 4419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk texType->compute(); 4429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk Allocation *cacheAlloc = new Allocation(mRSC, texType); 4449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mTextTexture.set(cacheAlloc); 4459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mTextTexture->deferedUploadToTexture(mRSC, false, 0); 4469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // Split up our cache texture into lines of certain widths 4489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk int nextLine = 0; 4499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0)); 4509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 4519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); 4529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 45394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); 45494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 4559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); 4569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 4579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); 4589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 4599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0)); 4609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 4619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0)); 4629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 4639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad 4659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initVertexArrayBuffers() 4669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 4679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // Now lets write index data 4689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1); 4699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk Type *indexType = new Type(mRSC); 4709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk uint32_t numIndicies = mMaxNumberOfQuads * 6; 4719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk indexType->setDimX(numIndicies); 4729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk indexType->setElement(indexElem); 4739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk indexType->compute(); 4749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk Allocation *indexAlloc = new Allocation(mRSC, indexType); 4769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr(); 4779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // Four verts, two triangles , six indices per quad 4799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) { 4809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk int i6 = i * 6; 4819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk int i4 = i * 4; 4829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk indexPtr[i6 + 0] = i4 + 0; 4849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk indexPtr[i6 + 1] = i4 + 1; 4859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk indexPtr[i6 + 2] = i4 + 2; 4869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk indexPtr[i6 + 3] = i4 + 0; 4889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk indexPtr[i6 + 4] = i4 + 2; 4899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk indexPtr[i6 + 5] = i4 + 3; 4909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 4919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk indexAlloc->deferedUploadToBufferObject(mRSC); 4939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mIndexBuffer.set(indexAlloc); 4949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3); 4969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2); 4979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 4989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk const Element *elemArray[2]; 4999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk elemArray[0] = posElem; 5009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk elemArray[1] = texElem; 5019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk String8 posName("position"); 5039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk String8 texName("texture0"); 5049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk const char *nameArray[2]; 5069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk nameArray[0] = posName.string(); 5079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk nameArray[1] = texName.string(); 5089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk size_t lengths[2]; 5099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk lengths[0] = posName.size(); 5109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk lengths[1] = texName.size(); 51170d4e5024298f71edb3b04867e05568f5495b4ceJason Sams uint32_t arraySizes[2] = {1, 1}; 5129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 51370d4e5024298f71edb3b04867e05568f5495b4ceJason Sams const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes); 5149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk Type *vertexDataType = new Type(mRSC); 5169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk vertexDataType->setDimX(mMaxNumberOfQuads * 4); 5179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk vertexDataType->setElement(vertexDataElem); 5189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk vertexDataType->compute(); 5199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType); 5219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mTextMeshPtr = (float*)vertexAlloc->getPtr(); 5229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mVertexArray.set(vertexAlloc); 5249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 5259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text 5279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::checkInit() 5289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 5299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(mInitialized) { 5309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk return; 5319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 5329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk initTextTexture(); 5349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk initRenderState(); 5359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk initVertexArrayBuffers(); 5379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 53827f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk // We store a string with letters in a rough frequency of occurrence 53927f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq"); 54027f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ"); 54127f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk mLatinPrecache += String8(",.?!()-+@;:`'"); 54227f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk mLatinPrecache += String8("0123456789"); 54327f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk 5449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mInitialized = true; 5459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 5469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::issueDrawCommand() { 5489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex()); 5509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mRSC->setVertex(mRSC->getDefaultProgramVertex()); 5519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 55280a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster()); 55380a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk mRSC->setRaster(mRSC->getDefaultProgramRaster()); 55480a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk 5559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment()); 5569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mRSC->setFragment(mFontShaderF.get()); 5579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore()); 5599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mRSC->setFragmentStore(mFontProgramStore.get()); 5609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 56155e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk if(mFontColorDirty) { 562c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk mFontShaderFConstant->data(mRSC, &mFontColor, 4*sizeof(float)); 56355e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk mFontColorDirty = false; 56455e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk } 56555e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk 5669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if (!mRSC->setupCheck()) { 5679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mRSC->setVertex((ProgramVertex *)tmpV.get()); 56880a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk mRSC->setRaster((ProgramRaster *)tmpR.get()); 5699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mRSC->setFragment((ProgramFragment *)tmpF.get()); 5709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 5719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk return; 5729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 5739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float *vtx = (float*)mVertexArray->getPtr(); 5759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float *tex = vtx + 3; 5769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk VertexArray va; 5784378f1175546616c76ecb7f0b1159940ab22d5f4Alex Sakhartchouk va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position"); 5794378f1175546616c76ecb7f0b1159940ab22d5f4Alex Sakhartchouk va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0"); 5809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache); 5819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mIndexBuffer->uploadCheck(mRSC); 5839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); 5849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0)); 5859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // Reset the state 5879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mRSC->setVertex((ProgramVertex *)tmpV.get()); 58880a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk mRSC->setRaster((ProgramRaster *)tmpR.get()); 5899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mRSC->setFragment((ProgramFragment *)tmpF.get()); 5909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 5919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 5929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 5939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1, 5949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float u1, float v1, 5959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float x2, float y2, float z2, 5969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float u2, float v2, 5979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float x3, float y3, float z3, 5989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float u3, float v3, 5999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float x4, float y4, float z4, 6009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float u4, float v4) 6019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 6029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk const uint32_t vertsPerQuad = 4; 6039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk const uint32_t floatsPerVert = 5; 6049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 6059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // Cull things that are off the screen 6079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float width = (float)mRSC->getWidth(); 6089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk float height = (float)mRSC->getHeight(); 6099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) { 6119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk return; 6129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 6139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1); 6159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk LOGE("V1 x: %f y: %f z: %f", x2, y2, z2); 6169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk LOGE("V2 x: %f y: %f z: %f", x3, y3, z3); 6179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/ 6189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = x1; 6209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = y1; 6219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = z1; 6229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = u1; 6239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = v1; 6249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = x2; 6269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = y2; 6279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = z2; 6289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = u2; 6299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = v2; 6309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = x3; 6329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = y3; 6339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = z3; 6349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = u3; 6359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = v3; 6369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = x4; 6389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = y4; 6399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = z4; 6409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = u4; 6419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk (*currentPos++) = v4; 6429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCurrentQuadIndex ++; 6449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(mCurrentQuadIndex == mMaxNumberOfQuads) { 6469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk issueDrawCommand(); 6479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCurrentQuadIndex = 0; 6489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 6499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 6509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 65194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() { 65294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk uint32_t remainingCapacity = 0; 65327f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk uint32_t totalPixels = 0; 65494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 65594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); 65694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk totalPixels += mCacheLines[i]->mMaxWidth; 65794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk } 65894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk remainingCapacity = (remainingCapacity * 100) / totalPixels; 65994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk return remainingCapacity; 66094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk} 66194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk 66294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukvoid FontState::precacheLatin(Font *font) { 66394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk // Remaining capacity is measured in % 66494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk uint32_t remainingCapacity = getRemainingCacheCapacity(); 66594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk uint32_t precacheIdx = 0; 66694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { 66794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]); 66894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk remainingCapacity = getRemainingCacheCapacity(); 66994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk precacheIdx ++; 67094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk } 67194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk} 67294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk 67394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk 6749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y) 6759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 6769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk checkInit(); 6779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk // Render code here 6799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk Font *currentFont = mRSC->getFont(); 680071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk if(!currentFont) { 681071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk if(!mDefault.get()) { 682071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96)); 683071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk } 684071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk currentFont = mDefault.get(); 685071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk } 686b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk if(!currentFont) { 687b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk LOGE("Unable to initialize any fonts"); 688b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk return; 689b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk } 690b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk 6919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y); 6929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(mCurrentQuadIndex != 0) { 6949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk issueDrawCommand(); 6959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mCurrentQuadIndex = 0; 6969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 6979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 6989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 6999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(const char *text, int x, int y) 7009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 7019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk size_t textLen = strlen(text); 7029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk renderText(text, textLen, 0, -1, x, y); 7039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 7049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 7059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(Allocation *alloc, int x, int y) 7069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 7079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(!alloc) { 7089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk return; 7099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 7109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 7119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk const char *text = (const char *)alloc->getPtr(); 7129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk size_t allocSize = alloc->getType()->getSizeBytes(); 7139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk renderText(text, allocSize, 0, -1, x, y); 7149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 7159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 7169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y) 7179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 7189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk if(!alloc) { 7199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk return; 7209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 7219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 7229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk const char *text = (const char *)alloc->getPtr(); 7239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk size_t allocSize = alloc->getType()->getSizeBytes(); 7249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk renderText(text, allocSize, start, len, x, y); 7259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 7269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 727fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) { 728fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk mFontColor[0] = r; 729fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk mFontColor[1] = g; 730fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk mFontColor[2] = b; 731fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk mFontColor[3] = a; 732fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk mFontColorDirty = true; 733fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk} 734fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk 73555e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const { 73655e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk *r = mFontColor[0]; 73755e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk *g = mFontColor[1]; 73855e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk *b = mFontColor[2]; 73955e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk *a = mFontColor[3]; 74055e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk} 74155e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk 7429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::deinit(Context *rsc) 7439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 744071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk mInitialized = false; 745071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk 74601f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines mFontShaderFConstant.clear(); 74701f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines 748071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk mIndexBuffer.clear(); 749071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk mVertexArray.clear(); 750071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk 751071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk mFontShaderF.clear(); 752071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk mFontSampler.clear(); 753071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk mFontProgramStore.clear(); 754071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk 755071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk mTextTexture.clear(); 756071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 757071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk delete mCacheLines[i]; 7589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk } 759071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk mCacheLines.clear(); 7609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 7619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk mDefault.clear(); 762071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk 763b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk Vector<Font*> fontsToDereference = mActiveFonts; 764b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk for(uint32_t i = 0; i < fontsToDereference.size(); i ++) { 765b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk fontsToDereference[i]->zeroUserRef(); 766b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk } 767b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk 768071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk if(mLibrary) { 769071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk FT_Done_FreeType( mLibrary ); 770b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk mLibrary = NULL; 771071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk } 7729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 7739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 7749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace android { 7759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace renderscript { 7769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 7779b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) 7789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{ 779071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk Font *newFont = Font::create(rsc, name, fontSize, dpi); 780071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk if(newFont) { 781071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk newFont->incUserRef(); 782071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk } 783071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk return newFont; 7849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} 7859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk 7869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // renderscript 7879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // android 788