blob: cc2b76addf6590e272e0fb9b772cdb4b4a8678c4 [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{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -070039 mAllocFile = __FILE__;
40 mAllocLine = __LINE__;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070041 mInitialized = false;
42 mHasKerning = false;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -070043 mFace = NULL;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouka1ccecd2010-06-30 12:49:27 -070058 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-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 Sakhartchouk09c67352010-10-05 11:33:27 -070087void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y)
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070088{
89 FontState *state = &mRSC->mStateFont;
90
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070091 int32_t nPenX = x + glyph->mBitmapLeft;
92 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070093
Alex Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -070098
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070099 int32_t width = (int32_t) glyph->mBitmapWidth;
100 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700101
Alex Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700106}
107
Alex Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700160{
161 if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
162 return;
163 }
164
Alex Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-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 Sakhartchouk01bcef62010-08-17 11:09:49 -0700195 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-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 Sakhartchouk01bcef62010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700235void Font::updateGlyphCache(CachedGlyphInfo *glyph)
236{
Alex Sakhartchouka1ccecd2010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700241 }
242
Alex Sakhartchouka1ccecd2010-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 Sakhartchoukd3e0ad42010-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 Sakhartchouka1ccecd2010-06-30 12:49:27 -0700255 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700256
257 if(!glyph->mIsValid) {
258 return;
259 }
260
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700261 uint32_t endX = startX + bitmap->width;
262 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700263
264 glyph->mBitmapMinX = startX;
265 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700266 glyph->mBitmapWidth = bitmap->width;
267 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700285
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk35b96442010-08-18 15:46:43 -0700293 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700306 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700307 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-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 Sakhartchouk3659d942010-06-30 16:53:43 -0700341 mLibrary = NULL;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700342 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukc9fa3052010-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 Sakhartchouk09c67352010-10-05 11:33:27 -0700357 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-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 Sakhartchouk09c67352010-10-05 11:33:27 -0700368 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-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 Sakhartchoukd3e0ad42010-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 Sakhartchouka1ccecd2010-06-30 12:49:27 -0700392FT_Library FontState::getLib()
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700393{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700394 if(!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700395 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700396 if(error) {
397 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700398 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700399 }
400 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700401
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700402 return mLibrary;
403}
404
405void FontState::init(Context *rsc)
406{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700407 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700469 uint32_t cacheWidth = getCacheTextureType()->getDimX();
470
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700471 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
472 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk09c67352010-10-05 11:33:27 -0700477 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk383e5b12010-09-23 16:16:33 -0700485 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouke7ae69f2010-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 Sakhartchoukc9fa3052010-10-01 15:20:41 -0700504 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchouke7ae69f2010-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 Sakhartchoukc9fa3052010-10-01 15:20:41 -0700509 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700510 mRSC->mStateElement.elementBuilderBegin();
511 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700512 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchouke7ae69f2010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700529 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700530 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk383e5b12010-09-23 16:16:33 -0700535 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk09c67352010-10-05 11:33:27 -0700561 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk01bcef62010-08-17 11:09:49 -0700566 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
567 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk09c67352010-10-05 11:33:27 -0700593 int32_t i6 = i * 6;
594 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-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 Sams46e45542010-09-02 17:35:23 -0700624 uint32_t arraySizes[2] = {1, 1};
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700625
Jason Sams46e45542010-09-02 17:35:23 -0700626 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk35b96442010-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 Sakhartchoukd3e0ad42010-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 Sakhartchoukd18c7442010-07-12 15:50:32 -0700665 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
666 mRSC->setRaster(mRSC->getDefaultProgramRaster());
667
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukc9fa3052010-10-01 15:20:41 -0700674 if(mConstantsDirty) {
675 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
676 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700677 }
678
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700679 if (!mRSC->setupCheck()) {
680 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700681 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk886f11a2010-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 Sakhartchoukd3e0ad42010-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 Sakhartchoukd18c7442010-07-12 15:50:32 -0700701 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouk01bcef62010-08-17 11:09:49 -0700764uint32_t FontState::getRemainingCacheCapacity() {
765 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700766 uint32_t totalPixels = 0;
Alex Sakhartchouk01bcef62010-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 Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700792{
793 checkInit();
794
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700795 // Render code here
796 Font *currentFont = mRSC->getFont();
Alex Sakhartchouka1ccecd2010-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 Sakhartchouk3659d942010-06-30 16:53:43 -0700803 if(!currentFont) {
804 LOGE("Unable to initialize any fonts");
805 return;
806 }
807
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700808 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
809 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700810
811 if(mCurrentQuadIndex != 0) {
812 issueDrawCommand();
813 mCurrentQuadIndex = 0;
814 }
815}
816
Alex Sakhartchouk09c67352010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700819}
820
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700821void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-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 Sakhartchouk09c67352010-10-05 11:33:27 -0700828 const int32_t luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-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 Sakhartchouk9fc9f032010-08-04 14:45:48 -0700835}
836
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700837void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-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 Sakhartchoukca5a4542010-08-05 11:24:14 -0700842}
843
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700844void FontState::deinit(Context *rsc)
845{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700846 mInitialized = false;
847
Stephen Hines01b7d292010-09-28 15:45:45 -0700848 mFontShaderFConstant.clear();
849
Alex Sakhartchouka1ccecd2010-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 Sakhartchouk3659d942010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700870 if(mLibrary) {
871 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700872 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700873 }
Alex Sakhartchoukd3e0ad42010-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 Sakhartchouka1ccecd2010-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 Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700886}
887
888} // renderscript
889} // android