blob: 66f455c026c06f20f35e2e303d998da1c419b8e3 [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{
39 mInitialized = false;
40 mHasKerning = false;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -070041 mFace = NULL;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouka1ccecd2010-06-30 12:49:27 -070056 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-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 Sakhartchouk09c67352010-10-05 11:33:27 -070085void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y)
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070086{
87 FontState *state = &mRSC->mStateFont;
88
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070089 int32_t nPenX = x + glyph->mBitmapLeft;
90 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070091
Alex Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -070096
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070097 int32_t width = (int32_t) glyph->mBitmapWidth;
98 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070099
Alex Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700104}
105
Alex Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700158{
159 if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
160 return;
161 }
162
Alex Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-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 Sakhartchouk01bcef62010-08-17 11:09:49 -0700193 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-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 Sakhartchouk01bcef62010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700233void Font::updateGlyphCache(CachedGlyphInfo *glyph)
234{
Alex Sakhartchouka1ccecd2010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700239 }
240
Alex Sakhartchouka1ccecd2010-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 Sakhartchoukd3e0ad42010-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 Sakhartchouka1ccecd2010-06-30 12:49:27 -0700253 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700254
255 if(!glyph->mIsValid) {
256 return;
257 }
258
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700259 uint32_t endX = startX + bitmap->width;
260 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700261
262 glyph->mBitmapMinX = startX;
263 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700264 glyph->mBitmapWidth = bitmap->width;
265 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700283
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk35b96442010-08-18 15:46:43 -0700291 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700304 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700305 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700306 return newFont;
307 }
308
Jason Sams225afd32010-10-21 14:06:55 -0700309 ObjectBase::checkDelete(newFont);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-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 Sakhartchouk3659d942010-06-30 16:53:43 -0700339 mLibrary = NULL;
Alex Sakhartchoukc9fa3052010-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 Sakhartchouk09c67352010-10-05 11:33:27 -0700354 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-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 Sakhartchouk09c67352010-10-05 11:33:27 -0700365 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-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 Sakhartchouk4f230b32010-10-12 14:15:17 -0700378
379 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouka1ccecd2010-06-30 12:49:27 -0700391FT_Library FontState::getLib()
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700392{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700393 if(!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700394 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700395 if(error) {
396 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700397 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700398 }
399 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700400
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700401 return mLibrary;
402}
403
404void FontState::init(Context *rsc)
405{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700406 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700468 uint32_t cacheWidth = getCacheTextureType()->getDimX();
469
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700470 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
471 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk09c67352010-10-05 11:33:27 -0700476 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk383e5b12010-09-23 16:16:33 -0700484 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk7ffcaf22010-10-06 11:15:01 -0700499 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchouke7ae69f2010-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 Sakhartchoukc9fa3052010-10-01 15:20:41 -0700503 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchouke7ae69f2010-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 Sakhartchoukc9fa3052010-10-01 15:20:41 -0700508 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700509 mRSC->mStateElement.elementBuilderBegin();
510 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700511 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700512 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
513
Jason Samsf0c1df42010-10-26 13:09:17 -0700514 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchouke7ae69f2010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700525 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700526 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk383e5b12010-09-23 16:16:33 -0700531 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchoukd3e0ad42010-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 Samsf0c1df42010-10-26 13:09:17 -0700546 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk09c67352010-10-05 11:33:27 -0700553 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk01bcef62010-08-17 11:09:49 -0700558 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
559 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700574 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Samsf0c1df42010-10-26 13:09:17 -0700575 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk09c67352010-10-05 11:33:27 -0700582 int32_t i6 = i * 6;
583 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk64cd98e2010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700604
Jason Samsf0c1df42010-10-26 13:09:17 -0700605 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
606 mMaxNumberOfQuads * 4,
607 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk35b96442010-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 Sakhartchoukd3e0ad42010-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 Sakhartchoukd18c7442010-07-12 15:50:32 -0700641 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
642 mRSC->setRaster(mRSC->getDefaultProgramRaster());
643
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukc9fa3052010-10-01 15:20:41 -0700650 if(mConstantsDirty) {
651 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
652 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700653 }
654
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700655 if (!mRSC->setupCheck()) {
656 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700657 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-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
Alex Sakhartchouk54929cc2010-11-08 15:10:52 -0800666 VertexArray::Attrib attribs[2];
667 attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
668 attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
669 VertexArray va(attribs, 2);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700670 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
671
672 mIndexBuffer->uploadCheck(mRSC);
673 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
674 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
675
676 // Reset the state
677 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700678 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700679 mRSC->setFragment((ProgramFragment *)tmpF.get());
680 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
681}
682
683void FontState::appendMeshQuad(float x1, float y1, float z1,
684 float u1, float v1,
685 float x2, float y2, float z2,
686 float u2, float v2,
687 float x3, float y3, float z3,
688 float u3, float v3,
689 float x4, float y4, float z4,
690 float u4, float v4)
691{
692 const uint32_t vertsPerQuad = 4;
693 const uint32_t floatsPerVert = 5;
694 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
695
696 // Cull things that are off the screen
697 float width = (float)mRSC->getWidth();
698 float height = (float)mRSC->getHeight();
699
700 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
701 return;
702 }
703
704 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
705 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
706 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
707 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
708
709 (*currentPos++) = x1;
710 (*currentPos++) = y1;
711 (*currentPos++) = z1;
712 (*currentPos++) = u1;
713 (*currentPos++) = v1;
714
715 (*currentPos++) = x2;
716 (*currentPos++) = y2;
717 (*currentPos++) = z2;
718 (*currentPos++) = u2;
719 (*currentPos++) = v2;
720
721 (*currentPos++) = x3;
722 (*currentPos++) = y3;
723 (*currentPos++) = z3;
724 (*currentPos++) = u3;
725 (*currentPos++) = v3;
726
727 (*currentPos++) = x4;
728 (*currentPos++) = y4;
729 (*currentPos++) = z4;
730 (*currentPos++) = u4;
731 (*currentPos++) = v4;
732
733 mCurrentQuadIndex ++;
734
735 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
736 issueDrawCommand();
737 mCurrentQuadIndex = 0;
738 }
739}
740
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700741uint32_t FontState::getRemainingCacheCapacity() {
742 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700743 uint32_t totalPixels = 0;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700744 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
745 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
746 totalPixels += mCacheLines[i]->mMaxWidth;
747 }
748 remainingCapacity = (remainingCapacity * 100) / totalPixels;
749 return remainingCapacity;
750}
751
752void FontState::precacheLatin(Font *font) {
753 // Remaining capacity is measured in %
754 uint32_t remainingCapacity = getRemainingCacheCapacity();
755 uint32_t precacheIdx = 0;
756 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
757 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
758 remainingCapacity = getRemainingCacheCapacity();
759 precacheIdx ++;
760 }
761}
762
763
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700764void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
765 uint32_t startIndex, int32_t numGlyphs,
766 Font::RenderMode mode,
767 Font::Rect *bounds,
768 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700769{
770 checkInit();
771
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700772 // Render code here
773 Font *currentFont = mRSC->getFont();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700774 if(!currentFont) {
775 if(!mDefault.get()) {
776 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
777 }
778 currentFont = mDefault.get();
779 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700780 if(!currentFont) {
781 LOGE("Unable to initialize any fonts");
782 return;
783 }
784
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700785 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
786 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700787
788 if(mCurrentQuadIndex != 0) {
789 issueDrawCommand();
790 mCurrentQuadIndex = 0;
791 }
792}
793
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700794void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
795 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700796}
797
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700798void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700799 mConstants.mFontColor[0] = r;
800 mConstants.mFontColor[1] = g;
801 mConstants.mFontColor[2] = b;
802 mConstants.mFontColor[3] = a;
803
804 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700805 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700806 if (luminance <= mBlackThreshold) {
807 mConstants.mGamma = mBlackGamma;
808 } else if (luminance >= mWhiteThreshold) {
809 mConstants.mGamma = mWhiteGamma;
810 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700811
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700812 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700813}
814
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700815void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700816 *r = mConstants.mFontColor[0];
817 *g = mConstants.mFontColor[1];
818 *b = mConstants.mFontColor[2];
819 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700820}
821
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700822void FontState::deinit(Context *rsc)
823{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700824 mInitialized = false;
825
Stephen Hines01b7d292010-09-28 15:45:45 -0700826 mFontShaderFConstant.clear();
827
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700828 mIndexBuffer.clear();
829 mVertexArray.clear();
830
831 mFontShaderF.clear();
832 mFontSampler.clear();
833 mFontProgramStore.clear();
834
835 mTextTexture.clear();
836 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
837 delete mCacheLines[i];
838 }
839 mCacheLines.clear();
840
841 mDefault.clear();
842
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700843 Vector<Font*> fontsToDereference = mActiveFonts;
844 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
845 fontsToDereference[i]->zeroUserRef();
846 }
847
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700848 if(mLibrary) {
849 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700850 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700851 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700852}
853
854namespace android {
855namespace renderscript {
856
857RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
858{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700859 Font *newFont = Font::create(rsc, name, fontSize, dpi);
860 if(newFont) {
861 newFont->incUserRef();
862 }
863 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700864}
865
866} // renderscript
867} // android