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