blob: 9e76215297272946910aff07ad0829145ca4a4ae [file] [log] [blame]
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -070026#include <cutils/properties.h>
Alex Sakhartchouk9b949fc2010-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{
39 mInitialized = false;
40 mHasKerning = false;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -070041 mFace = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070042}
43
44bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi)
45{
46 if(mInitialized) {
47 LOGE("Reinitialization of fonts not supported");
48 return false;
49 }
50
51 String8 fontsDir("/fonts/");
52 String8 fullPath(getenv("ANDROID_ROOT"));
53 fullPath += fontsDir;
54 fullPath += name;
55
Alex Sakhartchouk071508d2010-06-30 12:49:27 -070056 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070057 if(error) {
58 LOGE("Unable to initialize font %s", fullPath.string());
59 return false;
60 }
61
62 mFontName = name;
63 mFontSize = fontSize;
64 mDpi = dpi;
65
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070066 error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
67 if(error) {
68 LOGE("Unable to set font size on %s", fullPath.string());
69 return false;
70 }
71
72 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070073
74 mInitialized = true;
75 return true;
76}
77
78void Font::invalidateTextureCache()
79{
80 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
81 mCachedGlyphs.valueAt(i)->mIsValid = false;
82 }
83}
84
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070085void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y)
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070086{
87 FontState *state = &mRSC->mStateFont;
88
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070089 int32_t nPenX = x + glyph->mBitmapLeft;
90 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070091
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070092 float u1 = glyph->mBitmapMinU;
93 float u2 = glyph->mBitmapMaxU;
94 float v1 = glyph->mBitmapMinV;
95 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070096
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070097 int32_t width = (int32_t) glyph->mBitmapWidth;
98 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070099
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700100 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
101 nPenX + width, nPenY, 0, u2, v2,
102 nPenX + width, nPenY - height, 0, u2, v1,
103 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700104}
105
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700106void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
107 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
108 int32_t nPenX = x + glyph->mBitmapLeft;
109 int32_t nPenY = y + glyph->mBitmapTop;
110
111 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
112 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
113
114 FontState *state = &mRSC->mStateFont;
115 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
116 const uint8_t* cacheBuffer = state->getTextTextureData();
117
118 uint32_t cacheX = 0, cacheY = 0;
119 int32_t bX = 0, bY = 0;
120 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
121 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
122 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
123 LOGE("Skipping invalid index");
124 continue;
125 }
126 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
127 bitmap[bY * bitmapW + bX] = tempCol;
128 }
129 }
130
131}
132
133void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
134 int32_t nPenX = x + glyph->mBitmapLeft;
135 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
136
137 int32_t width = (int32_t) glyph->mBitmapWidth;
138 int32_t height = (int32_t) glyph->mBitmapHeight;
139
140 if (bounds->bottom > nPenY) {
141 bounds->bottom = nPenY;
142 }
143 if (bounds->left > nPenX) {
144 bounds->left = nPenX;
145 }
146 if (bounds->right < nPenX + width) {
147 bounds->right = nPenX + width;
148 }
149 if (bounds->top < nPenY + height) {
150 bounds->top = nPenY + height;
151 }
152}
153
154void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
155 uint32_t start, int32_t numGlyphs,
156 RenderMode mode, Rect *bounds,
157 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700158{
159 if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
160 return;
161 }
162
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700163 if(mode == Font::MEASURE) {
164 if (bounds == NULL) {
165 LOGE("No return rectangle provided to measure text");
166 return;
167 }
168 // Reset min and max of the bounding box to something large
169 bounds->set(1e6, -1e6, -1e6, 1e6);
170 }
171
172 int32_t penX = x, penY = y;
173 int32_t glyphsLeft = 1;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700174 if(numGlyphs > 0) {
175 glyphsLeft = numGlyphs;
176 }
177
178 size_t index = start;
179 size_t nextIndex = 0;
180
181 while (glyphsLeft > 0) {
182
183 int32_t utfChar = utf32_at(text, len, index, &nextIndex);
184
185 // Reached the end of the string or encountered
186 if(utfChar < 0) {
187 break;
188 }
189
190 // Move to the next character in the array
191 index = nextIndex;
192
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700193 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700194
195 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
196 if(cachedGlyph->mIsValid) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700197 switch(mode) {
198 case FRAMEBUFFER:
199 drawCachedGlyph(cachedGlyph, penX, penY);
200 break;
201 case BITMAP:
202 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
203 break;
204 case MEASURE:
205 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
206 break;
207 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700208 }
209
210 penX += (cachedGlyph->mAdvance.x >> 6);
211
212 // If we were given a specific number of glyphs, decrement
213 if(numGlyphs > 0) {
214 glyphsLeft --;
215 }
216 }
217}
218
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700219Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
220
221 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
222 if(cachedGlyph == NULL) {
223 cachedGlyph = cacheGlyph((uint32_t)utfChar);
224 }
225 // Is the glyph still in texture cache?
226 if(!cachedGlyph->mIsValid) {
227 updateGlyphCache(cachedGlyph);
228 }
229
230 return cachedGlyph;
231}
232
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700233void Font::updateGlyphCache(CachedGlyphInfo *glyph)
234{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700235 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
236 if(error) {
237 LOGE("Couldn't load glyph.");
238 return;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700239 }
240
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700241 glyph->mAdvance = mFace->glyph->advance;
242 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
243 glyph->mBitmapTop = mFace->glyph->bitmap_top;
244
245 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
246
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700247 // Now copy the bitmap into the cache texture
248 uint32_t startX = 0;
249 uint32_t startY = 0;
250
251 // Let the font state figure out where to put the bitmap
252 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700253 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700254
255 if(!glyph->mIsValid) {
256 return;
257 }
258
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700259 uint32_t endX = startX + bitmap->width;
260 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700261
262 glyph->mBitmapMinX = startX;
263 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700264 glyph->mBitmapWidth = bitmap->width;
265 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700266
267 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
268 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
269
270 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
271 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
272 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
273 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
274}
275
276Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
277{
278 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
279 mCachedGlyphs.add(glyph, newGlyph);
280
281 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
282 newGlyph->mIsValid = false;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700283
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700284 updateGlyphCache(newGlyph);
285
286 return newGlyph;
287}
288
289Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
290{
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700291 rsc->mStateFont.checkInit();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700292 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
293
294 for(uint32_t i = 0; i < activeFonts.size(); i ++) {
295 Font *ithFont = activeFonts[i];
296 if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700297 return ithFont;
298 }
299 }
300
301 Font *newFont = new Font(rsc);
302 bool isInitialized = newFont->init(name, fontSize, dpi);
303 if(isInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700304 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700305 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700306 return newFont;
307 }
308
Jason Samsb38d5342010-10-21 14:06:55 -0700309 ObjectBase::checkDelete(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700310 return NULL;
311
312}
313
314Font::~Font()
315{
316 if(mFace) {
317 FT_Done_Face(mFace);
318 }
319
320 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
321 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
322 mRSC->mStateFont.mActiveFonts.removeAt(ct);
323 break;
324 }
325 }
326
327 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
328 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700329 delete glyph;
330 }
331}
332
333FontState::FontState()
334{
335 mInitialized = false;
336 mMaxNumberOfQuads = 1024;
337 mCurrentQuadIndex = 0;
338 mRSC = NULL;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700339 mLibrary = NULL;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700340
341 // Get the renderer properties
342 char property[PROPERTY_VALUE_MAX];
343
344 // Get the gamma
345 float gamma = DEFAULT_TEXT_GAMMA;
346 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
347 LOGD(" Setting text gamma to %s", property);
348 gamma = atof(property);
349 } else {
350 LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
351 }
352
353 // Get the black gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700354 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700355 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
356 LOGD(" Setting text black gamma threshold to %s", property);
357 blackThreshold = atoi(property);
358 } else {
359 LOGD(" Using default text black gamma threshold of %d",
360 DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
361 }
362 mBlackThreshold = (float)(blackThreshold) / 255.0f;
363
364 // Get the white gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700365 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700366 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
367 LOGD(" Setting text white gamma threshold to %s", property);
368 whiteThreshold = atoi(property);
369 } else {
370 LOGD(" Using default white black gamma threshold of %d",
371 DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
372 }
373 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
374
375 // Compute the gamma tables
376 mBlackGamma = gamma;
377 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700378
379 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700380}
381
382FontState::~FontState()
383{
384 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
385 delete mCacheLines[i];
386 }
387
388 rsAssert(!mActiveFonts.size());
389}
390
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700391FT_Library FontState::getLib()
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700392{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700393 if(!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700394 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700395 if(error) {
396 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700397 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700398 }
399 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700400
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700401 return mLibrary;
402}
403
404void FontState::init(Context *rsc)
405{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700406 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700407}
408
409void FontState::flushAllAndInvalidate()
410{
411 if(mCurrentQuadIndex != 0) {
412 issueDrawCommand();
413 mCurrentQuadIndex = 0;
414 }
415 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
416 mActiveFonts[i]->invalidateTextureCache();
417 }
418 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
419 mCacheLines[i]->mCurrentCol = 0;
420 }
421}
422
423bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
424{
425 // If the glyph is too tall, don't cache it
426 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
427 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
428 return false;
429 }
430
431 // Now copy the bitmap into the cache texture
432 uint32_t startX = 0;
433 uint32_t startY = 0;
434
435 bool bitmapFit = false;
436 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
437 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
438 if(bitmapFit) {
439 break;
440 }
441 }
442
443 // If the new glyph didn't fit, flush the state so far and invalidate everything
444 if(!bitmapFit) {
445 flushAllAndInvalidate();
446
447 // Try to fit it again
448 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
449 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
450 if(bitmapFit) {
451 break;
452 }
453 }
454
455 // if we still don't fit, something is wrong and we shouldn't draw
456 if(!bitmapFit) {
457 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
458 return false;
459 }
460 }
461
462 *retOriginX = startX;
463 *retOriginY = startY;
464
465 uint32_t endX = startX + bitmap->width;
466 uint32_t endY = startY + bitmap->rows;
467
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700468 uint32_t cacheWidth = getCacheTextureType()->getDimX();
469
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700470 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
471 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700472
473 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
474 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
475 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700476 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700477 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
478 }
479 }
480
481 // This will dirty the texture and the shader so next time
482 // we draw it will upload the data
483 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700484 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700485
486 // Some debug code
487 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
488 LOGE("Cache Line: H: %u Empty Space: %f",
489 mCacheLines[i]->mMaxHeight,
490 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
491
492 }*/
493
494 return true;
495}
496
497void FontState::initRenderState()
498{
Alex Sakhartchoukd2091632010-10-06 11:15:01 -0700499 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700500 shaderString.append("void main() {\n");
501 shaderString.append(" lowp vec4 col = UNI_Color;\n");
502 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700503 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700504 shaderString.append(" gl_FragColor = col;\n");
505 shaderString.append("}\n");
506
507 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700508 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700509 mRSC->mStateElement.elementBuilderBegin();
510 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700511 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700512 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
513
Jason Sams31a7e422010-10-26 13:09:17 -0700514 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700515
516 uint32_t tmp[4];
517 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
518 tmp[1] = (uint32_t)inputType;
519 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
520 tmp[3] = 1;
521
522 mFontShaderFConstant.set(new Allocation(mRSC, inputType));
523 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
524 shaderString.length(), tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700525 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700526 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700527
528 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
529 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
530 mFontSampler.set(sampler);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700531 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700532
533 ProgramStore *fontStore = new ProgramStore(mRSC);
534 mFontProgramStore.set(fontStore);
535 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
536 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
537 mFontProgramStore->setDitherEnable(false);
538 mFontProgramStore->setDepthMask(false);
539}
540
541void FontState::initTextTexture()
542{
543 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
544
545 // We will allocate a texture to initially hold 32 character bitmaps
Jason Sams31a7e422010-10-26 13:09:17 -0700546 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700547
548 Allocation *cacheAlloc = new Allocation(mRSC, texType);
549 mTextTexture.set(cacheAlloc);
550 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
551
552 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700553 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700554 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
555 nextLine += mCacheLines.top()->mMaxHeight;
556 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
557 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700558 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
559 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700560 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
561 nextLine += mCacheLines.top()->mMaxHeight;
562 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
563 nextLine += mCacheLines.top()->mMaxHeight;
564 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
565 nextLine += mCacheLines.top()->mMaxHeight;
566 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
567}
568
569// Avoid having to reallocate memory and render quad by quad
570void FontState::initVertexArrayBuffers()
571{
572 // Now lets write index data
573 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700574 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Sams31a7e422010-10-26 13:09:17 -0700575 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700576
577 Allocation *indexAlloc = new Allocation(mRSC, indexType);
578 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
579
580 // Four verts, two triangles , six indices per quad
581 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700582 int32_t i6 = i * 6;
583 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700584
585 indexPtr[i6 + 0] = i4 + 0;
586 indexPtr[i6 + 1] = i4 + 1;
587 indexPtr[i6 + 2] = i4 + 2;
588
589 indexPtr[i6 + 3] = i4 + 0;
590 indexPtr[i6 + 4] = i4 + 2;
591 indexPtr[i6 + 5] = i4 + 3;
592 }
593
594 indexAlloc->deferedUploadToBufferObject(mRSC);
595 mIndexBuffer.set(indexAlloc);
596
597 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
598 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
599
Alex Sakhartchouk98bfe5d2010-10-18 17:18:50 -0700600 mRSC->mStateElement.elementBuilderBegin();
601 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
602 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
603 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700604
Jason Sams31a7e422010-10-26 13:09:17 -0700605 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
606 mMaxNumberOfQuads * 4,
607 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700608
609 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
610 mTextMeshPtr = (float*)vertexAlloc->getPtr();
611
612 mVertexArray.set(vertexAlloc);
613}
614
615// We don't want to allocate anything unless we actually draw text
616void FontState::checkInit()
617{
618 if(mInitialized) {
619 return;
620 }
621
622 initTextTexture();
623 initRenderState();
624
625 initVertexArrayBuffers();
626
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700627 // We store a string with letters in a rough frequency of occurrence
628 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
629 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
630 mLatinPrecache += String8(",.?!()-+@;:`'");
631 mLatinPrecache += String8("0123456789");
632
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700633 mInitialized = true;
634}
635
636void FontState::issueDrawCommand() {
637
638 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
639 mRSC->setVertex(mRSC->getDefaultProgramVertex());
640
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700641 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
642 mRSC->setRaster(mRSC->getDefaultProgramRaster());
643
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700644 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
645 mRSC->setFragment(mFontShaderF.get());
646
647 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
648 mRSC->setFragmentStore(mFontProgramStore.get());
649
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700650 if(mConstantsDirty) {
651 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
652 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700653 }
654
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700655 if (!mRSC->setupCheck()) {
656 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700657 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700658 mRSC->setFragment((ProgramFragment *)tmpF.get());
659 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
660 return;
661 }
662
663 float *vtx = (float*)mVertexArray->getPtr();
664 float *tex = vtx + 3;
665
666 VertexArray va;
Alex Sakhartchouk4378f112010-09-29 09:49:13 -0700667 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
668 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700669 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
670
671 mIndexBuffer->uploadCheck(mRSC);
672 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
673 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
674
675 // Reset the state
676 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700677 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700678 mRSC->setFragment((ProgramFragment *)tmpF.get());
679 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
680}
681
682void FontState::appendMeshQuad(float x1, float y1, float z1,
683 float u1, float v1,
684 float x2, float y2, float z2,
685 float u2, float v2,
686 float x3, float y3, float z3,
687 float u3, float v3,
688 float x4, float y4, float z4,
689 float u4, float v4)
690{
691 const uint32_t vertsPerQuad = 4;
692 const uint32_t floatsPerVert = 5;
693 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
694
695 // Cull things that are off the screen
696 float width = (float)mRSC->getWidth();
697 float height = (float)mRSC->getHeight();
698
699 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
700 return;
701 }
702
703 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
704 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
705 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
706 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
707
708 (*currentPos++) = x1;
709 (*currentPos++) = y1;
710 (*currentPos++) = z1;
711 (*currentPos++) = u1;
712 (*currentPos++) = v1;
713
714 (*currentPos++) = x2;
715 (*currentPos++) = y2;
716 (*currentPos++) = z2;
717 (*currentPos++) = u2;
718 (*currentPos++) = v2;
719
720 (*currentPos++) = x3;
721 (*currentPos++) = y3;
722 (*currentPos++) = z3;
723 (*currentPos++) = u3;
724 (*currentPos++) = v3;
725
726 (*currentPos++) = x4;
727 (*currentPos++) = y4;
728 (*currentPos++) = z4;
729 (*currentPos++) = u4;
730 (*currentPos++) = v4;
731
732 mCurrentQuadIndex ++;
733
734 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
735 issueDrawCommand();
736 mCurrentQuadIndex = 0;
737 }
738}
739
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700740uint32_t FontState::getRemainingCacheCapacity() {
741 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700742 uint32_t totalPixels = 0;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700743 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
744 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
745 totalPixels += mCacheLines[i]->mMaxWidth;
746 }
747 remainingCapacity = (remainingCapacity * 100) / totalPixels;
748 return remainingCapacity;
749}
750
751void FontState::precacheLatin(Font *font) {
752 // Remaining capacity is measured in %
753 uint32_t remainingCapacity = getRemainingCacheCapacity();
754 uint32_t precacheIdx = 0;
755 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
756 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
757 remainingCapacity = getRemainingCacheCapacity();
758 precacheIdx ++;
759 }
760}
761
762
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700763void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
764 uint32_t startIndex, int32_t numGlyphs,
765 Font::RenderMode mode,
766 Font::Rect *bounds,
767 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700768{
769 checkInit();
770
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700771 // Render code here
772 Font *currentFont = mRSC->getFont();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700773 if(!currentFont) {
774 if(!mDefault.get()) {
775 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
776 }
777 currentFont = mDefault.get();
778 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700779 if(!currentFont) {
780 LOGE("Unable to initialize any fonts");
781 return;
782 }
783
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700784 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
785 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700786
787 if(mCurrentQuadIndex != 0) {
788 issueDrawCommand();
789 mCurrentQuadIndex = 0;
790 }
791}
792
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700793void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
794 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700795}
796
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700797void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700798 mConstants.mFontColor[0] = r;
799 mConstants.mFontColor[1] = g;
800 mConstants.mFontColor[2] = b;
801 mConstants.mFontColor[3] = a;
802
803 mConstants.mGamma = 1.0f;
Alex Sakhartchouk76322af2010-10-05 13:23:55 -0700804 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700805 if (luminance <= mBlackThreshold) {
806 mConstants.mGamma = mBlackGamma;
807 } else if (luminance >= mWhiteThreshold) {
808 mConstants.mGamma = mWhiteGamma;
809 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700810
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700811 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700812}
813
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700814void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700815 *r = mConstants.mFontColor[0];
816 *g = mConstants.mFontColor[1];
817 *b = mConstants.mFontColor[2];
818 *a = mConstants.mFontColor[3];
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700819}
820
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700821void FontState::deinit(Context *rsc)
822{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700823 mInitialized = false;
824
Stephen Hines01f0ad72010-09-28 15:45:45 -0700825 mFontShaderFConstant.clear();
826
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700827 mIndexBuffer.clear();
828 mVertexArray.clear();
829
830 mFontShaderF.clear();
831 mFontSampler.clear();
832 mFontProgramStore.clear();
833
834 mTextTexture.clear();
835 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
836 delete mCacheLines[i];
837 }
838 mCacheLines.clear();
839
840 mDefault.clear();
841
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700842 Vector<Font*> fontsToDereference = mActiveFonts;
843 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
844 fontsToDereference[i]->zeroUserRef();
845 }
846
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700847 if(mLibrary) {
848 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700849 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700850 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700851}
852
853namespace android {
854namespace renderscript {
855
856RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
857{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700858 Font *newFont = Font::create(rsc, name, fontSize, dpi);
859 if(newFont) {
860 newFont->incUserRef();
861 }
862 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700863}
864
865} // renderscript
866} // android