blob: 8756f82341f77e103b82e2cddb03a852a1be2ed4 [file] [log] [blame]
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -07001
2/*
3 * Copyright (C) 2009 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#ifndef ANDROID_RS_BUILD_FOR_HOST
19#include "rsContext.h"
20#else
21#include "rsContextHostStub.h"
22#endif
23
24#include "rsFont.h"
25#include "rsProgramFragment.h"
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -070026#include <cutils/properties.h>
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070027#include FT_BITMAP_H
28
29#include <GLES/gl.h>
30#include <GLES/glext.h>
31#include <GLES2/gl2.h>
32#include <GLES2/gl2ext.h>
33
34using namespace android;
35using namespace android::renderscript;
36
37Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL)
38{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -070039 mAllocFile = __FILE__;
40 mAllocLine = __LINE__;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070041 mInitialized = false;
42 mHasKerning = false;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -070043 mFace = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070044}
45
46bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi)
47{
48 if(mInitialized) {
49 LOGE("Reinitialization of fonts not supported");
50 return false;
51 }
52
53 String8 fontsDir("/fonts/");
54 String8 fullPath(getenv("ANDROID_ROOT"));
55 fullPath += fontsDir;
56 fullPath += name;
57
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -070058 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070059 if(error) {
60 LOGE("Unable to initialize font %s", fullPath.string());
61 return false;
62 }
63
64 mFontName = name;
65 mFontSize = fontSize;
66 mDpi = dpi;
67
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070068 error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
69 if(error) {
70 LOGE("Unable to set font size on %s", fullPath.string());
71 return false;
72 }
73
74 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070075
76 mInitialized = true;
77 return true;
78}
79
80void Font::invalidateTextureCache()
81{
82 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
83 mCachedGlyphs.valueAt(i)->mIsValid = false;
84 }
85}
86
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070087void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y)
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070088{
89 FontState *state = &mRSC->mStateFont;
90
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070091 int32_t nPenX = x + glyph->mBitmapLeft;
92 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070093
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070094 float u1 = glyph->mBitmapMinU;
95 float u2 = glyph->mBitmapMaxU;
96 float v1 = glyph->mBitmapMinV;
97 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070098
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070099 int32_t width = (int32_t) glyph->mBitmapWidth;
100 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700101
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700102 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
103 nPenX + width, nPenY, 0, u2, v2,
104 nPenX + width, nPenY - height, 0, u2, v1,
105 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700106}
107
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700108void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
109 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
110 int32_t nPenX = x + glyph->mBitmapLeft;
111 int32_t nPenY = y + glyph->mBitmapTop;
112
113 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
114 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
115
116 FontState *state = &mRSC->mStateFont;
117 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
118 const uint8_t* cacheBuffer = state->getTextTextureData();
119
120 uint32_t cacheX = 0, cacheY = 0;
121 int32_t bX = 0, bY = 0;
122 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
123 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
124 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
125 LOGE("Skipping invalid index");
126 continue;
127 }
128 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
129 bitmap[bY * bitmapW + bX] = tempCol;
130 }
131 }
132
133}
134
135void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
136 int32_t nPenX = x + glyph->mBitmapLeft;
137 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
138
139 int32_t width = (int32_t) glyph->mBitmapWidth;
140 int32_t height = (int32_t) glyph->mBitmapHeight;
141
142 if (bounds->bottom > nPenY) {
143 bounds->bottom = nPenY;
144 }
145 if (bounds->left > nPenX) {
146 bounds->left = nPenX;
147 }
148 if (bounds->right < nPenX + width) {
149 bounds->right = nPenX + width;
150 }
151 if (bounds->top < nPenY + height) {
152 bounds->top = nPenY + height;
153 }
154}
155
156void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
157 uint32_t start, int32_t numGlyphs,
158 RenderMode mode, Rect *bounds,
159 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700160{
161 if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
162 return;
163 }
164
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700165 if(mode == Font::MEASURE) {
166 if (bounds == NULL) {
167 LOGE("No return rectangle provided to measure text");
168 return;
169 }
170 // Reset min and max of the bounding box to something large
171 bounds->set(1e6, -1e6, -1e6, 1e6);
172 }
173
174 int32_t penX = x, penY = y;
175 int32_t glyphsLeft = 1;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700176 if(numGlyphs > 0) {
177 glyphsLeft = numGlyphs;
178 }
179
180 size_t index = start;
181 size_t nextIndex = 0;
182
183 while (glyphsLeft > 0) {
184
185 int32_t utfChar = utf32_at(text, len, index, &nextIndex);
186
187 // Reached the end of the string or encountered
188 if(utfChar < 0) {
189 break;
190 }
191
192 // Move to the next character in the array
193 index = nextIndex;
194
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700195 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700196
197 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
198 if(cachedGlyph->mIsValid) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700199 switch(mode) {
200 case FRAMEBUFFER:
201 drawCachedGlyph(cachedGlyph, penX, penY);
202 break;
203 case BITMAP:
204 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
205 break;
206 case MEASURE:
207 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
208 break;
209 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700210 }
211
212 penX += (cachedGlyph->mAdvance.x >> 6);
213
214 // If we were given a specific number of glyphs, decrement
215 if(numGlyphs > 0) {
216 glyphsLeft --;
217 }
218 }
219}
220
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700221Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
222
223 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
224 if(cachedGlyph == NULL) {
225 cachedGlyph = cacheGlyph((uint32_t)utfChar);
226 }
227 // Is the glyph still in texture cache?
228 if(!cachedGlyph->mIsValid) {
229 updateGlyphCache(cachedGlyph);
230 }
231
232 return cachedGlyph;
233}
234
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700235void Font::updateGlyphCache(CachedGlyphInfo *glyph)
236{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700237 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
238 if(error) {
239 LOGE("Couldn't load glyph.");
240 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700241 }
242
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700243 glyph->mAdvance = mFace->glyph->advance;
244 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
245 glyph->mBitmapTop = mFace->glyph->bitmap_top;
246
247 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
248
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700249 // Now copy the bitmap into the cache texture
250 uint32_t startX = 0;
251 uint32_t startY = 0;
252
253 // Let the font state figure out where to put the bitmap
254 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700255 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700256
257 if(!glyph->mIsValid) {
258 return;
259 }
260
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700261 uint32_t endX = startX + bitmap->width;
262 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700263
264 glyph->mBitmapMinX = startX;
265 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700266 glyph->mBitmapWidth = bitmap->width;
267 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700268
269 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
270 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
271
272 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
273 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
274 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
275 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
276}
277
278Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
279{
280 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
281 mCachedGlyphs.add(glyph, newGlyph);
282
283 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
284 newGlyph->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700285
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700286 updateGlyphCache(newGlyph);
287
288 return newGlyph;
289}
290
291Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
292{
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700293 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700294 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
295
296 for(uint32_t i = 0; i < activeFonts.size(); i ++) {
297 Font *ithFont = activeFonts[i];
298 if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700299 return ithFont;
300 }
301 }
302
303 Font *newFont = new Font(rsc);
304 bool isInitialized = newFont->init(name, fontSize, dpi);
305 if(isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700306 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700307 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700308 return newFont;
309 }
310
311 delete newFont;
312 return NULL;
313
314}
315
316Font::~Font()
317{
318 if(mFace) {
319 FT_Done_Face(mFace);
320 }
321
322 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
323 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
324 mRSC->mStateFont.mActiveFonts.removeAt(ct);
325 break;
326 }
327 }
328
329 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
330 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700331 delete glyph;
332 }
333}
334
335FontState::FontState()
336{
337 mInitialized = false;
338 mMaxNumberOfQuads = 1024;
339 mCurrentQuadIndex = 0;
340 mRSC = NULL;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700341 mLibrary = NULL;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700342
343 // Get the renderer properties
344 char property[PROPERTY_VALUE_MAX];
345
346 // Get the gamma
347 float gamma = DEFAULT_TEXT_GAMMA;
348 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
349 LOGD(" Setting text gamma to %s", property);
350 gamma = atof(property);
351 } else {
352 LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
353 }
354
355 // Get the black gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700356 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700357 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
358 LOGD(" Setting text black gamma threshold to %s", property);
359 blackThreshold = atoi(property);
360 } else {
361 LOGD(" Using default text black gamma threshold of %d",
362 DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
363 }
364 mBlackThreshold = (float)(blackThreshold) / 255.0f;
365
366 // Get the white gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700367 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700368 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
369 LOGD(" Setting text white gamma threshold to %s", property);
370 whiteThreshold = atoi(property);
371 } else {
372 LOGD(" Using default white black gamma threshold of %d",
373 DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
374 }
375 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
376
377 // Compute the gamma tables
378 mBlackGamma = gamma;
379 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700380
381 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700382}
383
384FontState::~FontState()
385{
386 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
387 delete mCacheLines[i];
388 }
389
390 rsAssert(!mActiveFonts.size());
391}
392
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700393FT_Library FontState::getLib()
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700394{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700395 if(!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700396 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700397 if(error) {
398 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700399 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700400 }
401 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700402
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700403 return mLibrary;
404}
405
406void FontState::init(Context *rsc)
407{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700408 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700409}
410
411void FontState::flushAllAndInvalidate()
412{
413 if(mCurrentQuadIndex != 0) {
414 issueDrawCommand();
415 mCurrentQuadIndex = 0;
416 }
417 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
418 mActiveFonts[i]->invalidateTextureCache();
419 }
420 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
421 mCacheLines[i]->mCurrentCol = 0;
422 }
423}
424
425bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
426{
427 // If the glyph is too tall, don't cache it
428 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
429 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
430 return false;
431 }
432
433 // Now copy the bitmap into the cache texture
434 uint32_t startX = 0;
435 uint32_t startY = 0;
436
437 bool bitmapFit = false;
438 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
439 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
440 if(bitmapFit) {
441 break;
442 }
443 }
444
445 // If the new glyph didn't fit, flush the state so far and invalidate everything
446 if(!bitmapFit) {
447 flushAllAndInvalidate();
448
449 // Try to fit it again
450 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
451 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
452 if(bitmapFit) {
453 break;
454 }
455 }
456
457 // if we still don't fit, something is wrong and we shouldn't draw
458 if(!bitmapFit) {
459 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
460 return false;
461 }
462 }
463
464 *retOriginX = startX;
465 *retOriginY = startY;
466
467 uint32_t endX = startX + bitmap->width;
468 uint32_t endY = startY + bitmap->rows;
469
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700470 uint32_t cacheWidth = getCacheTextureType()->getDimX();
471
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700472 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
473 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700474
475 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
476 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
477 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700478 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700479 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
480 }
481 }
482
483 // This will dirty the texture and the shader so next time
484 // we draw it will upload the data
485 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700486 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700487
488 // Some debug code
489 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
490 LOGE("Cache Line: H: %u Empty Space: %f",
491 mCacheLines[i]->mMaxHeight,
492 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
493
494 }*/
495
496 return true;
497}
498
499void FontState::initRenderState()
500{
Alex Sakhartchouk7ffcaf22010-10-06 11:15:01 -0700501 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700502 shaderString.append("void main() {\n");
503 shaderString.append(" lowp vec4 col = UNI_Color;\n");
504 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700505 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700506 shaderString.append(" gl_FragColor = col;\n");
507 shaderString.append("}\n");
508
509 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700510 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700511 mRSC->mStateElement.elementBuilderBegin();
512 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700513 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700514 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
515
516 Type *inputType = new Type(mRSC);
517 inputType->setElement(constInput);
518 inputType->setDimX(1);
519 inputType->compute();
520
521 uint32_t tmp[4];
522 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
523 tmp[1] = (uint32_t)inputType;
524 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
525 tmp[3] = 1;
526
527 mFontShaderFConstant.set(new Allocation(mRSC, inputType));
528 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
529 shaderString.length(), tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700530 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700531 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700532
533 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
534 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
535 mFontSampler.set(sampler);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700536 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700537
538 ProgramStore *fontStore = new ProgramStore(mRSC);
539 mFontProgramStore.set(fontStore);
540 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
541 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
542 mFontProgramStore->setDitherEnable(false);
543 mFontProgramStore->setDepthMask(false);
544}
545
546void FontState::initTextTexture()
547{
548 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
549
550 // We will allocate a texture to initially hold 32 character bitmaps
551 Type *texType = new Type(mRSC);
552 texType->setElement(alphaElem);
553 texType->setDimX(1024);
554 texType->setDimY(256);
555 texType->compute();
556
557 Allocation *cacheAlloc = new Allocation(mRSC, texType);
558 mTextTexture.set(cacheAlloc);
559 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
560
561 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700562 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700563 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
564 nextLine += mCacheLines.top()->mMaxHeight;
565 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
566 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700567 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
568 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700569 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
570 nextLine += mCacheLines.top()->mMaxHeight;
571 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
572 nextLine += mCacheLines.top()->mMaxHeight;
573 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
574 nextLine += mCacheLines.top()->mMaxHeight;
575 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
576}
577
578// Avoid having to reallocate memory and render quad by quad
579void FontState::initVertexArrayBuffers()
580{
581 // Now lets write index data
582 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
583 Type *indexType = new Type(mRSC);
584 uint32_t numIndicies = mMaxNumberOfQuads * 6;
585 indexType->setDimX(numIndicies);
586 indexType->setElement(indexElem);
587 indexType->compute();
588
589 Allocation *indexAlloc = new Allocation(mRSC, indexType);
590 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
591
592 // Four verts, two triangles , six indices per quad
593 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700594 int32_t i6 = i * 6;
595 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700596
597 indexPtr[i6 + 0] = i4 + 0;
598 indexPtr[i6 + 1] = i4 + 1;
599 indexPtr[i6 + 2] = i4 + 2;
600
601 indexPtr[i6 + 3] = i4 + 0;
602 indexPtr[i6 + 4] = i4 + 2;
603 indexPtr[i6 + 5] = i4 + 3;
604 }
605
606 indexAlloc->deferedUploadToBufferObject(mRSC);
607 mIndexBuffer.set(indexAlloc);
608
609 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
610 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
611
612 const Element *elemArray[2];
613 elemArray[0] = posElem;
614 elemArray[1] = texElem;
615
616 String8 posName("position");
617 String8 texName("texture0");
618
619 const char *nameArray[2];
620 nameArray[0] = posName.string();
621 nameArray[1] = texName.string();
622 size_t lengths[2];
623 lengths[0] = posName.size();
624 lengths[1] = texName.size();
Jason Sams46e45542010-09-02 17:35:23 -0700625 uint32_t arraySizes[2] = {1, 1};
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700626
Jason Sams46e45542010-09-02 17:35:23 -0700627 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700628
629 Type *vertexDataType = new Type(mRSC);
630 vertexDataType->setDimX(mMaxNumberOfQuads * 4);
631 vertexDataType->setElement(vertexDataElem);
632 vertexDataType->compute();
633
634 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
635 mTextMeshPtr = (float*)vertexAlloc->getPtr();
636
637 mVertexArray.set(vertexAlloc);
638}
639
640// We don't want to allocate anything unless we actually draw text
641void FontState::checkInit()
642{
643 if(mInitialized) {
644 return;
645 }
646
647 initTextTexture();
648 initRenderState();
649
650 initVertexArrayBuffers();
651
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700652 // We store a string with letters in a rough frequency of occurrence
653 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
654 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
655 mLatinPrecache += String8(",.?!()-+@;:`'");
656 mLatinPrecache += String8("0123456789");
657
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700658 mInitialized = true;
659}
660
661void FontState::issueDrawCommand() {
662
663 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
664 mRSC->setVertex(mRSC->getDefaultProgramVertex());
665
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700666 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
667 mRSC->setRaster(mRSC->getDefaultProgramRaster());
668
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700669 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
670 mRSC->setFragment(mFontShaderF.get());
671
672 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
673 mRSC->setFragmentStore(mFontProgramStore.get());
674
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700675 if(mConstantsDirty) {
676 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
677 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700678 }
679
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700680 if (!mRSC->setupCheck()) {
681 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700682 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700683 mRSC->setFragment((ProgramFragment *)tmpF.get());
684 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
685 return;
686 }
687
688 float *vtx = (float*)mVertexArray->getPtr();
689 float *tex = vtx + 3;
690
691 VertexArray va;
Alex Sakhartchouk886f11a2010-09-29 09:49:13 -0700692 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
693 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700694 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
695
696 mIndexBuffer->uploadCheck(mRSC);
697 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
698 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
699
700 // Reset the state
701 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700702 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700703 mRSC->setFragment((ProgramFragment *)tmpF.get());
704 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
705}
706
707void FontState::appendMeshQuad(float x1, float y1, float z1,
708 float u1, float v1,
709 float x2, float y2, float z2,
710 float u2, float v2,
711 float x3, float y3, float z3,
712 float u3, float v3,
713 float x4, float y4, float z4,
714 float u4, float v4)
715{
716 const uint32_t vertsPerQuad = 4;
717 const uint32_t floatsPerVert = 5;
718 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
719
720 // Cull things that are off the screen
721 float width = (float)mRSC->getWidth();
722 float height = (float)mRSC->getHeight();
723
724 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
725 return;
726 }
727
728 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
729 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
730 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
731 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
732
733 (*currentPos++) = x1;
734 (*currentPos++) = y1;
735 (*currentPos++) = z1;
736 (*currentPos++) = u1;
737 (*currentPos++) = v1;
738
739 (*currentPos++) = x2;
740 (*currentPos++) = y2;
741 (*currentPos++) = z2;
742 (*currentPos++) = u2;
743 (*currentPos++) = v2;
744
745 (*currentPos++) = x3;
746 (*currentPos++) = y3;
747 (*currentPos++) = z3;
748 (*currentPos++) = u3;
749 (*currentPos++) = v3;
750
751 (*currentPos++) = x4;
752 (*currentPos++) = y4;
753 (*currentPos++) = z4;
754 (*currentPos++) = u4;
755 (*currentPos++) = v4;
756
757 mCurrentQuadIndex ++;
758
759 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
760 issueDrawCommand();
761 mCurrentQuadIndex = 0;
762 }
763}
764
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700765uint32_t FontState::getRemainingCacheCapacity() {
766 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700767 uint32_t totalPixels = 0;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700768 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
769 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
770 totalPixels += mCacheLines[i]->mMaxWidth;
771 }
772 remainingCapacity = (remainingCapacity * 100) / totalPixels;
773 return remainingCapacity;
774}
775
776void FontState::precacheLatin(Font *font) {
777 // Remaining capacity is measured in %
778 uint32_t remainingCapacity = getRemainingCacheCapacity();
779 uint32_t precacheIdx = 0;
780 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
781 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
782 remainingCapacity = getRemainingCacheCapacity();
783 precacheIdx ++;
784 }
785}
786
787
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700788void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
789 uint32_t startIndex, int32_t numGlyphs,
790 Font::RenderMode mode,
791 Font::Rect *bounds,
792 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700793{
794 checkInit();
795
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700796 // Render code here
797 Font *currentFont = mRSC->getFont();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700798 if(!currentFont) {
799 if(!mDefault.get()) {
800 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
801 }
802 currentFont = mDefault.get();
803 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700804 if(!currentFont) {
805 LOGE("Unable to initialize any fonts");
806 return;
807 }
808
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700809 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
810 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700811
812 if(mCurrentQuadIndex != 0) {
813 issueDrawCommand();
814 mCurrentQuadIndex = 0;
815 }
816}
817
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700818void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
819 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700820}
821
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700822void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700823 mConstants.mFontColor[0] = r;
824 mConstants.mFontColor[1] = g;
825 mConstants.mFontColor[2] = b;
826 mConstants.mFontColor[3] = a;
827
828 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700829 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700830 if (luminance <= mBlackThreshold) {
831 mConstants.mGamma = mBlackGamma;
832 } else if (luminance >= mWhiteThreshold) {
833 mConstants.mGamma = mWhiteGamma;
834 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700835
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700836 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700837}
838
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700839void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700840 *r = mConstants.mFontColor[0];
841 *g = mConstants.mFontColor[1];
842 *b = mConstants.mFontColor[2];
843 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700844}
845
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700846void FontState::deinit(Context *rsc)
847{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700848 mInitialized = false;
849
Stephen Hines01b7d292010-09-28 15:45:45 -0700850 mFontShaderFConstant.clear();
851
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700852 mIndexBuffer.clear();
853 mVertexArray.clear();
854
855 mFontShaderF.clear();
856 mFontSampler.clear();
857 mFontProgramStore.clear();
858
859 mTextTexture.clear();
860 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
861 delete mCacheLines[i];
862 }
863 mCacheLines.clear();
864
865 mDefault.clear();
866
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700867 Vector<Font*> fontsToDereference = mActiveFonts;
868 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
869 fontsToDereference[i]->zeroUserRef();
870 }
871
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700872 if(mLibrary) {
873 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700874 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700875 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700876}
877
878namespace android {
879namespace renderscript {
880
881RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
882{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700883 Font *newFont = Font::create(rsc, name, fontSize, dpi);
884 if(newFont) {
885 newFont->incUserRef();
886 }
887 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700888}
889
890} // renderscript
891} // android