blob: d171a48154f2983c8c3acad04e64e9d4e8463773 [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
514 Type *inputType = new Type(mRSC);
515 inputType->setElement(constInput);
516 inputType->setDimX(1);
517 inputType->compute();
518
519 uint32_t tmp[4];
520 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
521 tmp[1] = (uint32_t)inputType;
522 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
523 tmp[3] = 1;
524
525 mFontShaderFConstant.set(new Allocation(mRSC, inputType));
526 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
527 shaderString.length(), tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700528 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700529 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700530
531 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
532 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
533 mFontSampler.set(sampler);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700534 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700535
536 ProgramStore *fontStore = new ProgramStore(mRSC);
537 mFontProgramStore.set(fontStore);
538 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
539 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
540 mFontProgramStore->setDitherEnable(false);
541 mFontProgramStore->setDepthMask(false);
542}
543
544void FontState::initTextTexture()
545{
546 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
547
548 // We will allocate a texture to initially hold 32 character bitmaps
549 Type *texType = new Type(mRSC);
550 texType->setElement(alphaElem);
551 texType->setDimX(1024);
552 texType->setDimY(256);
553 texType->compute();
554
555 Allocation *cacheAlloc = new Allocation(mRSC, texType);
556 mTextTexture.set(cacheAlloc);
557 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
558
559 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700560 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700561 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
562 nextLine += mCacheLines.top()->mMaxHeight;
563 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
564 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700565 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
566 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700567 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
568 nextLine += mCacheLines.top()->mMaxHeight;
569 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
570 nextLine += mCacheLines.top()->mMaxHeight;
571 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
572 nextLine += mCacheLines.top()->mMaxHeight;
573 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
574}
575
576// Avoid having to reallocate memory and render quad by quad
577void FontState::initVertexArrayBuffers()
578{
579 // Now lets write index data
580 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
581 Type *indexType = new Type(mRSC);
582 uint32_t numIndicies = mMaxNumberOfQuads * 6;
583 indexType->setDimX(numIndicies);
584 indexType->setElement(indexElem);
585 indexType->compute();
586
587 Allocation *indexAlloc = new Allocation(mRSC, indexType);
588 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
589
590 // Four verts, two triangles , six indices per quad
591 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700592 int32_t i6 = i * 6;
593 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700594
595 indexPtr[i6 + 0] = i4 + 0;
596 indexPtr[i6 + 1] = i4 + 1;
597 indexPtr[i6 + 2] = i4 + 2;
598
599 indexPtr[i6 + 3] = i4 + 0;
600 indexPtr[i6 + 4] = i4 + 2;
601 indexPtr[i6 + 5] = i4 + 3;
602 }
603
604 indexAlloc->deferedUploadToBufferObject(mRSC);
605 mIndexBuffer.set(indexAlloc);
606
607 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
608 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
609
Alex Sakhartchouk98bfe5d2010-10-18 17:18:50 -0700610 mRSC->mStateElement.elementBuilderBegin();
611 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
612 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
613 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700614
615 Type *vertexDataType = new Type(mRSC);
616 vertexDataType->setDimX(mMaxNumberOfQuads * 4);
617 vertexDataType->setElement(vertexDataElem);
618 vertexDataType->compute();
619
620 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
621 mTextMeshPtr = (float*)vertexAlloc->getPtr();
622
623 mVertexArray.set(vertexAlloc);
624}
625
626// We don't want to allocate anything unless we actually draw text
627void FontState::checkInit()
628{
629 if(mInitialized) {
630 return;
631 }
632
633 initTextTexture();
634 initRenderState();
635
636 initVertexArrayBuffers();
637
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700638 // We store a string with letters in a rough frequency of occurrence
639 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
640 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
641 mLatinPrecache += String8(",.?!()-+@;:`'");
642 mLatinPrecache += String8("0123456789");
643
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700644 mInitialized = true;
645}
646
647void FontState::issueDrawCommand() {
648
649 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
650 mRSC->setVertex(mRSC->getDefaultProgramVertex());
651
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700652 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
653 mRSC->setRaster(mRSC->getDefaultProgramRaster());
654
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700655 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
656 mRSC->setFragment(mFontShaderF.get());
657
658 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
659 mRSC->setFragmentStore(mFontProgramStore.get());
660
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700661 if(mConstantsDirty) {
662 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
663 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700664 }
665
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700666 if (!mRSC->setupCheck()) {
667 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700668 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700669 mRSC->setFragment((ProgramFragment *)tmpF.get());
670 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
671 return;
672 }
673
674 float *vtx = (float*)mVertexArray->getPtr();
675 float *tex = vtx + 3;
676
677 VertexArray va;
Alex Sakhartchouk4378f112010-09-29 09:49:13 -0700678 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
679 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700680 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
681
682 mIndexBuffer->uploadCheck(mRSC);
683 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
684 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
685
686 // Reset the state
687 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700688 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700689 mRSC->setFragment((ProgramFragment *)tmpF.get());
690 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
691}
692
693void FontState::appendMeshQuad(float x1, float y1, float z1,
694 float u1, float v1,
695 float x2, float y2, float z2,
696 float u2, float v2,
697 float x3, float y3, float z3,
698 float u3, float v3,
699 float x4, float y4, float z4,
700 float u4, float v4)
701{
702 const uint32_t vertsPerQuad = 4;
703 const uint32_t floatsPerVert = 5;
704 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
705
706 // Cull things that are off the screen
707 float width = (float)mRSC->getWidth();
708 float height = (float)mRSC->getHeight();
709
710 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
711 return;
712 }
713
714 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
715 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
716 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
717 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
718
719 (*currentPos++) = x1;
720 (*currentPos++) = y1;
721 (*currentPos++) = z1;
722 (*currentPos++) = u1;
723 (*currentPos++) = v1;
724
725 (*currentPos++) = x2;
726 (*currentPos++) = y2;
727 (*currentPos++) = z2;
728 (*currentPos++) = u2;
729 (*currentPos++) = v2;
730
731 (*currentPos++) = x3;
732 (*currentPos++) = y3;
733 (*currentPos++) = z3;
734 (*currentPos++) = u3;
735 (*currentPos++) = v3;
736
737 (*currentPos++) = x4;
738 (*currentPos++) = y4;
739 (*currentPos++) = z4;
740 (*currentPos++) = u4;
741 (*currentPos++) = v4;
742
743 mCurrentQuadIndex ++;
744
745 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
746 issueDrawCommand();
747 mCurrentQuadIndex = 0;
748 }
749}
750
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700751uint32_t FontState::getRemainingCacheCapacity() {
752 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700753 uint32_t totalPixels = 0;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700754 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
755 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
756 totalPixels += mCacheLines[i]->mMaxWidth;
757 }
758 remainingCapacity = (remainingCapacity * 100) / totalPixels;
759 return remainingCapacity;
760}
761
762void FontState::precacheLatin(Font *font) {
763 // Remaining capacity is measured in %
764 uint32_t remainingCapacity = getRemainingCacheCapacity();
765 uint32_t precacheIdx = 0;
766 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
767 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
768 remainingCapacity = getRemainingCacheCapacity();
769 precacheIdx ++;
770 }
771}
772
773
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700774void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
775 uint32_t startIndex, int32_t numGlyphs,
776 Font::RenderMode mode,
777 Font::Rect *bounds,
778 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700779{
780 checkInit();
781
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700782 // Render code here
783 Font *currentFont = mRSC->getFont();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700784 if(!currentFont) {
785 if(!mDefault.get()) {
786 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
787 }
788 currentFont = mDefault.get();
789 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700790 if(!currentFont) {
791 LOGE("Unable to initialize any fonts");
792 return;
793 }
794
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700795 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
796 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700797
798 if(mCurrentQuadIndex != 0) {
799 issueDrawCommand();
800 mCurrentQuadIndex = 0;
801 }
802}
803
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700804void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
805 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700806}
807
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700808void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700809 mConstants.mFontColor[0] = r;
810 mConstants.mFontColor[1] = g;
811 mConstants.mFontColor[2] = b;
812 mConstants.mFontColor[3] = a;
813
814 mConstants.mGamma = 1.0f;
Alex Sakhartchouk76322af2010-10-05 13:23:55 -0700815 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700816 if (luminance <= mBlackThreshold) {
817 mConstants.mGamma = mBlackGamma;
818 } else if (luminance >= mWhiteThreshold) {
819 mConstants.mGamma = mWhiteGamma;
820 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700821
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700822 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700823}
824
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700825void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700826 *r = mConstants.mFontColor[0];
827 *g = mConstants.mFontColor[1];
828 *b = mConstants.mFontColor[2];
829 *a = mConstants.mFontColor[3];
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700830}
831
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700832void FontState::deinit(Context *rsc)
833{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700834 mInitialized = false;
835
Stephen Hines01f0ad72010-09-28 15:45:45 -0700836 mFontShaderFConstant.clear();
837
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700838 mIndexBuffer.clear();
839 mVertexArray.clear();
840
841 mFontShaderF.clear();
842 mFontSampler.clear();
843 mFontProgramStore.clear();
844
845 mTextTexture.clear();
846 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
847 delete mCacheLines[i];
848 }
849 mCacheLines.clear();
850
851 mDefault.clear();
852
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700853 Vector<Font*> fontsToDereference = mActiveFonts;
854 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
855 fontsToDereference[i]->zeroUserRef();
856 }
857
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700858 if(mLibrary) {
859 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700860 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700861 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700862}
863
864namespace android {
865namespace renderscript {
866
867RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
868{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700869 Font *newFont = Font::create(rsc, name, fontSize, dpi);
870 if(newFont) {
871 newFont->incUserRef();
872 }
873 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700874}
875
876} // renderscript
877} // android