blob: cc2b76addf6590e272e0fb9b772cdb4b4a8678c4 [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 Sakhartchouk55e81982010-08-05 11:24:14 -0700342 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700343
344 // Get the renderer properties
345 char property[PROPERTY_VALUE_MAX];
346
347 // Get the gamma
348 float gamma = DEFAULT_TEXT_GAMMA;
349 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
350 LOGD(" Setting text gamma to %s", property);
351 gamma = atof(property);
352 } else {
353 LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
354 }
355
356 // Get the black gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700357 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700358 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
359 LOGD(" Setting text black gamma threshold to %s", property);
360 blackThreshold = atoi(property);
361 } else {
362 LOGD(" Using default text black gamma threshold of %d",
363 DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
364 }
365 mBlackThreshold = (float)(blackThreshold) / 255.0f;
366
367 // Get the white gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700368 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700369 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
370 LOGD(" Setting text white gamma threshold to %s", property);
371 whiteThreshold = atoi(property);
372 } else {
373 LOGD(" Using default white black gamma threshold of %d",
374 DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
375 }
376 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
377
378 // Compute the gamma tables
379 mBlackGamma = gamma;
380 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700381}
382
383FontState::~FontState()
384{
385 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
386 delete mCacheLines[i];
387 }
388
389 rsAssert(!mActiveFonts.size());
390}
391
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700392FT_Library FontState::getLib()
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700393{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700394 if(!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700395 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700396 if(error) {
397 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700398 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700399 }
400 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700401
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700402 return mLibrary;
403}
404
405void FontState::init(Context *rsc)
406{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700407 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700408}
409
410void FontState::flushAllAndInvalidate()
411{
412 if(mCurrentQuadIndex != 0) {
413 issueDrawCommand();
414 mCurrentQuadIndex = 0;
415 }
416 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
417 mActiveFonts[i]->invalidateTextureCache();
418 }
419 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
420 mCacheLines[i]->mCurrentCol = 0;
421 }
422}
423
424bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
425{
426 // If the glyph is too tall, don't cache it
427 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
428 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
429 return false;
430 }
431
432 // Now copy the bitmap into the cache texture
433 uint32_t startX = 0;
434 uint32_t startY = 0;
435
436 bool bitmapFit = false;
437 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
438 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
439 if(bitmapFit) {
440 break;
441 }
442 }
443
444 // If the new glyph didn't fit, flush the state so far and invalidate everything
445 if(!bitmapFit) {
446 flushAllAndInvalidate();
447
448 // Try to fit it again
449 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
450 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
451 if(bitmapFit) {
452 break;
453 }
454 }
455
456 // if we still don't fit, something is wrong and we shouldn't draw
457 if(!bitmapFit) {
458 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
459 return false;
460 }
461 }
462
463 *retOriginX = startX;
464 *retOriginY = startY;
465
466 uint32_t endX = startX + bitmap->width;
467 uint32_t endY = startY + bitmap->rows;
468
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700469 uint32_t cacheWidth = getCacheTextureType()->getDimX();
470
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700471 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
472 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700473
474 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
475 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
476 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700477 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700478 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
479 }
480 }
481
482 // This will dirty the texture and the shader so next time
483 // we draw it will upload the data
484 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700485 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700486
487 // Some debug code
488 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
489 LOGE("Cache Line: H: %u Empty Space: %f",
490 mCacheLines[i]->mMaxHeight,
491 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
492
493 }*/
494
495 return true;
496}
497
498void FontState::initRenderState()
499{
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700500 String8 shaderString("varying vec4 varTex0;\n");
501 shaderString.append("void main() {\n");
502 shaderString.append(" lowp vec4 col = UNI_Color;\n");
503 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700504 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700505 shaderString.append(" gl_FragColor = col;\n");
506 shaderString.append("}\n");
507
508 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700509 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700510 mRSC->mStateElement.elementBuilderBegin();
511 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700512 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700513 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
514
515 Type *inputType = new Type(mRSC);
516 inputType->setElement(constInput);
517 inputType->setDimX(1);
518 inputType->compute();
519
520 uint32_t tmp[4];
521 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
522 tmp[1] = (uint32_t)inputType;
523 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
524 tmp[3] = 1;
525
526 mFontShaderFConstant.set(new Allocation(mRSC, inputType));
527 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
528 shaderString.length(), tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700529 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700530 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700531
532 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
533 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
534 mFontSampler.set(sampler);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700535 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700536
537 ProgramStore *fontStore = new ProgramStore(mRSC);
538 mFontProgramStore.set(fontStore);
539 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
540 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
541 mFontProgramStore->setDitherEnable(false);
542 mFontProgramStore->setDepthMask(false);
543}
544
545void FontState::initTextTexture()
546{
547 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
548
549 // We will allocate a texture to initially hold 32 character bitmaps
550 Type *texType = new Type(mRSC);
551 texType->setElement(alphaElem);
552 texType->setDimX(1024);
553 texType->setDimY(256);
554 texType->compute();
555
556 Allocation *cacheAlloc = new Allocation(mRSC, texType);
557 mTextTexture.set(cacheAlloc);
558 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
559
560 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700561 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700562 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
563 nextLine += mCacheLines.top()->mMaxHeight;
564 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
565 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700566 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
567 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700568 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
569 nextLine += mCacheLines.top()->mMaxHeight;
570 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
571 nextLine += mCacheLines.top()->mMaxHeight;
572 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
573 nextLine += mCacheLines.top()->mMaxHeight;
574 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
575}
576
577// Avoid having to reallocate memory and render quad by quad
578void FontState::initVertexArrayBuffers()
579{
580 // Now lets write index data
581 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
582 Type *indexType = new Type(mRSC);
583 uint32_t numIndicies = mMaxNumberOfQuads * 6;
584 indexType->setDimX(numIndicies);
585 indexType->setElement(indexElem);
586 indexType->compute();
587
588 Allocation *indexAlloc = new Allocation(mRSC, indexType);
589 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
590
591 // Four verts, two triangles , six indices per quad
592 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700593 int32_t i6 = i * 6;
594 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700595
596 indexPtr[i6 + 0] = i4 + 0;
597 indexPtr[i6 + 1] = i4 + 1;
598 indexPtr[i6 + 2] = i4 + 2;
599
600 indexPtr[i6 + 3] = i4 + 0;
601 indexPtr[i6 + 4] = i4 + 2;
602 indexPtr[i6 + 5] = i4 + 3;
603 }
604
605 indexAlloc->deferedUploadToBufferObject(mRSC);
606 mIndexBuffer.set(indexAlloc);
607
608 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
609 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
610
611 const Element *elemArray[2];
612 elemArray[0] = posElem;
613 elemArray[1] = texElem;
614
615 String8 posName("position");
616 String8 texName("texture0");
617
618 const char *nameArray[2];
619 nameArray[0] = posName.string();
620 nameArray[1] = texName.string();
621 size_t lengths[2];
622 lengths[0] = posName.size();
623 lengths[1] = texName.size();
Jason Sams70d4e502010-09-02 17:35:23 -0700624 uint32_t arraySizes[2] = {1, 1};
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700625
Jason Sams70d4e502010-09-02 17:35:23 -0700626 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700627
628 Type *vertexDataType = new Type(mRSC);
629 vertexDataType->setDimX(mMaxNumberOfQuads * 4);
630 vertexDataType->setElement(vertexDataElem);
631 vertexDataType->compute();
632
633 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
634 mTextMeshPtr = (float*)vertexAlloc->getPtr();
635
636 mVertexArray.set(vertexAlloc);
637}
638
639// We don't want to allocate anything unless we actually draw text
640void FontState::checkInit()
641{
642 if(mInitialized) {
643 return;
644 }
645
646 initTextTexture();
647 initRenderState();
648
649 initVertexArrayBuffers();
650
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700651 // We store a string with letters in a rough frequency of occurrence
652 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
653 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
654 mLatinPrecache += String8(",.?!()-+@;:`'");
655 mLatinPrecache += String8("0123456789");
656
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700657 mInitialized = true;
658}
659
660void FontState::issueDrawCommand() {
661
662 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
663 mRSC->setVertex(mRSC->getDefaultProgramVertex());
664
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700665 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
666 mRSC->setRaster(mRSC->getDefaultProgramRaster());
667
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700668 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
669 mRSC->setFragment(mFontShaderF.get());
670
671 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
672 mRSC->setFragmentStore(mFontProgramStore.get());
673
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700674 if(mConstantsDirty) {
675 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
676 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700677 }
678
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700679 if (!mRSC->setupCheck()) {
680 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700681 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700682 mRSC->setFragment((ProgramFragment *)tmpF.get());
683 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
684 return;
685 }
686
687 float *vtx = (float*)mVertexArray->getPtr();
688 float *tex = vtx + 3;
689
690 VertexArray va;
Alex Sakhartchouk4378f112010-09-29 09:49:13 -0700691 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
692 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700693 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
694
695 mIndexBuffer->uploadCheck(mRSC);
696 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
697 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
698
699 // Reset the state
700 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700701 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700702 mRSC->setFragment((ProgramFragment *)tmpF.get());
703 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
704}
705
706void FontState::appendMeshQuad(float x1, float y1, float z1,
707 float u1, float v1,
708 float x2, float y2, float z2,
709 float u2, float v2,
710 float x3, float y3, float z3,
711 float u3, float v3,
712 float x4, float y4, float z4,
713 float u4, float v4)
714{
715 const uint32_t vertsPerQuad = 4;
716 const uint32_t floatsPerVert = 5;
717 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
718
719 // Cull things that are off the screen
720 float width = (float)mRSC->getWidth();
721 float height = (float)mRSC->getHeight();
722
723 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
724 return;
725 }
726
727 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
728 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
729 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
730 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
731
732 (*currentPos++) = x1;
733 (*currentPos++) = y1;
734 (*currentPos++) = z1;
735 (*currentPos++) = u1;
736 (*currentPos++) = v1;
737
738 (*currentPos++) = x2;
739 (*currentPos++) = y2;
740 (*currentPos++) = z2;
741 (*currentPos++) = u2;
742 (*currentPos++) = v2;
743
744 (*currentPos++) = x3;
745 (*currentPos++) = y3;
746 (*currentPos++) = z3;
747 (*currentPos++) = u3;
748 (*currentPos++) = v3;
749
750 (*currentPos++) = x4;
751 (*currentPos++) = y4;
752 (*currentPos++) = z4;
753 (*currentPos++) = u4;
754 (*currentPos++) = v4;
755
756 mCurrentQuadIndex ++;
757
758 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
759 issueDrawCommand();
760 mCurrentQuadIndex = 0;
761 }
762}
763
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700764uint32_t FontState::getRemainingCacheCapacity() {
765 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700766 uint32_t totalPixels = 0;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700767 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
768 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
769 totalPixels += mCacheLines[i]->mMaxWidth;
770 }
771 remainingCapacity = (remainingCapacity * 100) / totalPixels;
772 return remainingCapacity;
773}
774
775void FontState::precacheLatin(Font *font) {
776 // Remaining capacity is measured in %
777 uint32_t remainingCapacity = getRemainingCacheCapacity();
778 uint32_t precacheIdx = 0;
779 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
780 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
781 remainingCapacity = getRemainingCacheCapacity();
782 precacheIdx ++;
783 }
784}
785
786
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700787void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
788 uint32_t startIndex, int32_t numGlyphs,
789 Font::RenderMode mode,
790 Font::Rect *bounds,
791 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700792{
793 checkInit();
794
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700795 // Render code here
796 Font *currentFont = mRSC->getFont();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700797 if(!currentFont) {
798 if(!mDefault.get()) {
799 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
800 }
801 currentFont = mDefault.get();
802 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700803 if(!currentFont) {
804 LOGE("Unable to initialize any fonts");
805 return;
806 }
807
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700808 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
809 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700810
811 if(mCurrentQuadIndex != 0) {
812 issueDrawCommand();
813 mCurrentQuadIndex = 0;
814 }
815}
816
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700817void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
818 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700819}
820
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700821void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700822 mConstants.mFontColor[0] = r;
823 mConstants.mFontColor[1] = g;
824 mConstants.mFontColor[2] = b;
825 mConstants.mFontColor[3] = a;
826
827 mConstants.mGamma = 1.0f;
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700828 const int32_t luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700829 if (luminance <= mBlackThreshold) {
830 mConstants.mGamma = mBlackGamma;
831 } else if (luminance >= mWhiteThreshold) {
832 mConstants.mGamma = mWhiteGamma;
833 }
834 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700835}
836
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700837void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700838 *r = mConstants.mFontColor[0];
839 *g = mConstants.mFontColor[1];
840 *b = mConstants.mFontColor[2];
841 *a = mConstants.mFontColor[3];
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700842}
843
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700844void FontState::deinit(Context *rsc)
845{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700846 mInitialized = false;
847
Stephen Hines01f0ad72010-09-28 15:45:45 -0700848 mFontShaderFConstant.clear();
849
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700850 mIndexBuffer.clear();
851 mVertexArray.clear();
852
853 mFontShaderF.clear();
854 mFontSampler.clear();
855 mFontProgramStore.clear();
856
857 mTextTexture.clear();
858 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
859 delete mCacheLines[i];
860 }
861 mCacheLines.clear();
862
863 mDefault.clear();
864
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700865 Vector<Font*> fontsToDereference = mActiveFonts;
866 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
867 fontsToDereference[i]->zeroUserRef();
868 }
869
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700870 if(mLibrary) {
871 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700872 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700873 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700874}
875
876namespace android {
877namespace renderscript {
878
879RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
880{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700881 Font *newFont = Font::create(rsc, name, fontSize, dpi);
882 if(newFont) {
883 newFont->incUserRef();
884 }
885 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700886}
887
888} // renderscript
889} // android