blob: 0f815a2fa199b167eb113a3983bb1b6e06ed1df2 [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"
26#include FT_BITMAP_H
27
28#include <GLES/gl.h>
29#include <GLES/glext.h>
30#include <GLES2/gl2.h>
31#include <GLES2/gl2ext.h>
32
33using namespace android;
34using namespace android::renderscript;
35
36Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL)
37{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -070038 mAllocFile = __FILE__;
39 mAllocLine = __LINE__;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070040 mInitialized = false;
41 mHasKerning = false;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -070042 mFace = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070043}
44
45bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi)
46{
47 if(mInitialized) {
48 LOGE("Reinitialization of fonts not supported");
49 return false;
50 }
51
52 String8 fontsDir("/fonts/");
53 String8 fullPath(getenv("ANDROID_ROOT"));
54 fullPath += fontsDir;
55 fullPath += name;
56
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -070057 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070058 if(error) {
59 LOGE("Unable to initialize font %s", fullPath.string());
60 return false;
61 }
62
63 mFontName = name;
64 mFontSize = fontSize;
65 mDpi = dpi;
66
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070067 error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
68 if(error) {
69 LOGE("Unable to set font size on %s", fullPath.string());
70 return false;
71 }
72
73 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070074
75 mInitialized = true;
76 return true;
77}
78
79void Font::invalidateTextureCache()
80{
81 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
82 mCachedGlyphs.valueAt(i)->mIsValid = false;
83 }
84}
85
86void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y)
87{
88 FontState *state = &mRSC->mStateFont;
89
90 int nPenX = x + glyph->mBitmapLeft;
91 int nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
92
93 state->appendMeshQuad(nPenX, nPenY, 0,
94 glyph->mBitmapMinU, glyph->mBitmapMaxV,
95
96 nPenX + (int)glyph->mBitmapWidth, nPenY, 0,
97 glyph->mBitmapMaxU, glyph->mBitmapMaxV,
98
99 nPenX + (int)glyph->mBitmapWidth, nPenY - (int)glyph->mBitmapHeight, 0,
100 glyph->mBitmapMaxU, glyph->mBitmapMinV,
101
102 nPenX, nPenY - (int)glyph->mBitmapHeight, 0,
103 glyph->mBitmapMinU, glyph->mBitmapMinV);
104}
105
106void Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y)
107{
108 if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
109 return;
110 }
111
112 int penX = x, penY = y;
113 int glyphsLeft = 1;
114 if(numGlyphs > 0) {
115 glyphsLeft = numGlyphs;
116 }
117
118 size_t index = start;
119 size_t nextIndex = 0;
120
121 while (glyphsLeft > 0) {
122
123 int32_t utfChar = utf32_at(text, len, index, &nextIndex);
124
125 // Reached the end of the string or encountered
126 if(utfChar < 0) {
127 break;
128 }
129
130 // Move to the next character in the array
131 index = nextIndex;
132
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700133 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700134
135 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
136 if(cachedGlyph->mIsValid) {
137 drawCachedGlyph(cachedGlyph, penX, penY);
138 }
139
140 penX += (cachedGlyph->mAdvance.x >> 6);
141
142 // If we were given a specific number of glyphs, decrement
143 if(numGlyphs > 0) {
144 glyphsLeft --;
145 }
146 }
147}
148
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700149Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
150
151 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
152 if(cachedGlyph == NULL) {
153 cachedGlyph = cacheGlyph((uint32_t)utfChar);
154 }
155 // Is the glyph still in texture cache?
156 if(!cachedGlyph->mIsValid) {
157 updateGlyphCache(cachedGlyph);
158 }
159
160 return cachedGlyph;
161}
162
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700163void Font::updateGlyphCache(CachedGlyphInfo *glyph)
164{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700165 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
166 if(error) {
167 LOGE("Couldn't load glyph.");
168 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700169 }
170
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700171 glyph->mAdvance = mFace->glyph->advance;
172 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
173 glyph->mBitmapTop = mFace->glyph->bitmap_top;
174
175 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
176
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700177 // Now copy the bitmap into the cache texture
178 uint32_t startX = 0;
179 uint32_t startY = 0;
180
181 // Let the font state figure out where to put the bitmap
182 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700183 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700184
185 if(!glyph->mIsValid) {
186 return;
187 }
188
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700189 uint32_t endX = startX + bitmap->width;
190 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700191
192 glyph->mBitmapMinX = startX;
193 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700194 glyph->mBitmapWidth = bitmap->width;
195 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700196
197 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
198 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
199
200 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
201 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
202 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
203 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
204}
205
206Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
207{
208 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
209 mCachedGlyphs.add(glyph, newGlyph);
210
211 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
212 newGlyph->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700213
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700214 updateGlyphCache(newGlyph);
215
216 return newGlyph;
217}
218
219Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
220{
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700221 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700222 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
223
224 for(uint32_t i = 0; i < activeFonts.size(); i ++) {
225 Font *ithFont = activeFonts[i];
226 if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700227 return ithFont;
228 }
229 }
230
231 Font *newFont = new Font(rsc);
232 bool isInitialized = newFont->init(name, fontSize, dpi);
233 if(isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700234 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700235 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700236 return newFont;
237 }
238
239 delete newFont;
240 return NULL;
241
242}
243
244Font::~Font()
245{
246 if(mFace) {
247 FT_Done_Face(mFace);
248 }
249
250 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
251 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
252 mRSC->mStateFont.mActiveFonts.removeAt(ct);
253 break;
254 }
255 }
256
257 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
258 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700259 delete glyph;
260 }
261}
262
263FontState::FontState()
264{
265 mInitialized = false;
266 mMaxNumberOfQuads = 1024;
267 mCurrentQuadIndex = 0;
268 mRSC = NULL;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700269 mLibrary = NULL;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700270 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700271}
272
273FontState::~FontState()
274{
275 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
276 delete mCacheLines[i];
277 }
278
279 rsAssert(!mActiveFonts.size());
280}
281
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700282FT_Library FontState::getLib()
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700283{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700284 if(!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700285 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700286 if(error) {
287 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700288 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700289 }
290 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700291
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700292 return mLibrary;
293}
294
295void FontState::init(Context *rsc)
296{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700297 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700298}
299
300void FontState::flushAllAndInvalidate()
301{
302 if(mCurrentQuadIndex != 0) {
303 issueDrawCommand();
304 mCurrentQuadIndex = 0;
305 }
306 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
307 mActiveFonts[i]->invalidateTextureCache();
308 }
309 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
310 mCacheLines[i]->mCurrentCol = 0;
311 }
312}
313
314bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
315{
316 // If the glyph is too tall, don't cache it
317 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
318 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
319 return false;
320 }
321
322 // Now copy the bitmap into the cache texture
323 uint32_t startX = 0;
324 uint32_t startY = 0;
325
326 bool bitmapFit = false;
327 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
328 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
329 if(bitmapFit) {
330 break;
331 }
332 }
333
334 // If the new glyph didn't fit, flush the state so far and invalidate everything
335 if(!bitmapFit) {
336 flushAllAndInvalidate();
337
338 // Try to fit it again
339 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
340 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
341 if(bitmapFit) {
342 break;
343 }
344 }
345
346 // if we still don't fit, something is wrong and we shouldn't draw
347 if(!bitmapFit) {
348 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
349 return false;
350 }
351 }
352
353 *retOriginX = startX;
354 *retOriginY = startY;
355
356 uint32_t endX = startX + bitmap->width;
357 uint32_t endY = startY + bitmap->rows;
358
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700359 uint32_t cacheWidth = getCacheTextureType()->getDimX();
360
361 unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
362 unsigned char *bitmapBuffer = bitmap->buffer;
363
364 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
365 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
366 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
367 unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
368 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
369 }
370 }
371
372 // This will dirty the texture and the shader so next time
373 // we draw it will upload the data
374 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
375 mFontShaderF->bindTexture(0, mTextTexture.get());
376
377 // Some debug code
378 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
379 LOGE("Cache Line: H: %u Empty Space: %f",
380 mCacheLines[i]->mMaxHeight,
381 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
382
383 }*/
384
385 return true;
386}
387
388void FontState::initRenderState()
389{
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700390 String8 shaderString("varying vec4 varTex0;\n");
391 shaderString.append("void main() {\n");
392 shaderString.append(" lowp vec4 col = UNI_Color;\n");
393 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
394 shaderString.append(" gl_FragColor = col;\n");
395 shaderString.append("}\n");
396
397 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
398 mRSC->mStateElement.elementBuilderBegin();
399 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
400 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
401
402 Type *inputType = new Type(mRSC);
403 inputType->setElement(constInput);
404 inputType->setDimX(1);
405 inputType->compute();
406
407 uint32_t tmp[4];
408 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
409 tmp[1] = (uint32_t)inputType;
410 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
411 tmp[3] = 1;
412
413 mFontShaderFConstant.set(new Allocation(mRSC, inputType));
414 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
415 shaderString.length(), tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700416 mFontShaderF.set(pf);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700417 mFontShaderF->bindAllocation(mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700418
419 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
420 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
421 mFontSampler.set(sampler);
422 mFontShaderF->bindSampler(0, sampler);
423
424 ProgramStore *fontStore = new ProgramStore(mRSC);
425 mFontProgramStore.set(fontStore);
426 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
427 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
428 mFontProgramStore->setDitherEnable(false);
429 mFontProgramStore->setDepthMask(false);
430}
431
432void FontState::initTextTexture()
433{
434 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
435
436 // We will allocate a texture to initially hold 32 character bitmaps
437 Type *texType = new Type(mRSC);
438 texType->setElement(alphaElem);
439 texType->setDimX(1024);
440 texType->setDimY(256);
441 texType->compute();
442
443 Allocation *cacheAlloc = new Allocation(mRSC, texType);
444 mTextTexture.set(cacheAlloc);
445 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
446
447 // Split up our cache texture into lines of certain widths
448 int nextLine = 0;
449 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
450 nextLine += mCacheLines.top()->mMaxHeight;
451 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
452 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700453 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
454 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700455 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
456 nextLine += mCacheLines.top()->mMaxHeight;
457 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
458 nextLine += mCacheLines.top()->mMaxHeight;
459 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
460 nextLine += mCacheLines.top()->mMaxHeight;
461 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
462}
463
464// Avoid having to reallocate memory and render quad by quad
465void FontState::initVertexArrayBuffers()
466{
467 // Now lets write index data
468 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
469 Type *indexType = new Type(mRSC);
470 uint32_t numIndicies = mMaxNumberOfQuads * 6;
471 indexType->setDimX(numIndicies);
472 indexType->setElement(indexElem);
473 indexType->compute();
474
475 Allocation *indexAlloc = new Allocation(mRSC, indexType);
476 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
477
478 // Four verts, two triangles , six indices per quad
479 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
480 int i6 = i * 6;
481 int i4 = i * 4;
482
483 indexPtr[i6 + 0] = i4 + 0;
484 indexPtr[i6 + 1] = i4 + 1;
485 indexPtr[i6 + 2] = i4 + 2;
486
487 indexPtr[i6 + 3] = i4 + 0;
488 indexPtr[i6 + 4] = i4 + 2;
489 indexPtr[i6 + 5] = i4 + 3;
490 }
491
492 indexAlloc->deferedUploadToBufferObject(mRSC);
493 mIndexBuffer.set(indexAlloc);
494
495 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
496 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
497
498 const Element *elemArray[2];
499 elemArray[0] = posElem;
500 elemArray[1] = texElem;
501
502 String8 posName("position");
503 String8 texName("texture0");
504
505 const char *nameArray[2];
506 nameArray[0] = posName.string();
507 nameArray[1] = texName.string();
508 size_t lengths[2];
509 lengths[0] = posName.size();
510 lengths[1] = texName.size();
Jason Sams46e45542010-09-02 17:35:23 -0700511 uint32_t arraySizes[2] = {1, 1};
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700512
Jason Sams46e45542010-09-02 17:35:23 -0700513 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700514
515 Type *vertexDataType = new Type(mRSC);
516 vertexDataType->setDimX(mMaxNumberOfQuads * 4);
517 vertexDataType->setElement(vertexDataElem);
518 vertexDataType->compute();
519
520 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
521 mTextMeshPtr = (float*)vertexAlloc->getPtr();
522
523 mVertexArray.set(vertexAlloc);
524}
525
526// We don't want to allocate anything unless we actually draw text
527void FontState::checkInit()
528{
529 if(mInitialized) {
530 return;
531 }
532
533 initTextTexture();
534 initRenderState();
535
536 initVertexArrayBuffers();
537
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700538 // We store a string with letters in a rough frequency of occurrence
539 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
540 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
541 mLatinPrecache += String8(",.?!()-+@;:`'");
542 mLatinPrecache += String8("0123456789");
543
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700544 mInitialized = true;
545}
546
547void FontState::issueDrawCommand() {
548
549 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
550 mRSC->setVertex(mRSC->getDefaultProgramVertex());
551
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700552 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
553 mRSC->setRaster(mRSC->getDefaultProgramRaster());
554
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700555 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
556 mRSC->setFragment(mFontShaderF.get());
557
558 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
559 mRSC->setFragmentStore(mFontProgramStore.get());
560
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700561 if(mFontColorDirty) {
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700562 mFontShaderFConstant->data(mRSC, &mFontColor, 4*sizeof(float));
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700563 mFontColorDirty = false;
564 }
565
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700566 if (!mRSC->setupCheck()) {
567 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700568 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700569 mRSC->setFragment((ProgramFragment *)tmpF.get());
570 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
571 return;
572 }
573
574 float *vtx = (float*)mVertexArray->getPtr();
575 float *tex = vtx + 3;
576
577 VertexArray va;
578 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
579 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
580 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
581
582 mIndexBuffer->uploadCheck(mRSC);
583 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
584 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
585
586 // Reset the state
587 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700588 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700589 mRSC->setFragment((ProgramFragment *)tmpF.get());
590 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
591}
592
593void FontState::appendMeshQuad(float x1, float y1, float z1,
594 float u1, float v1,
595 float x2, float y2, float z2,
596 float u2, float v2,
597 float x3, float y3, float z3,
598 float u3, float v3,
599 float x4, float y4, float z4,
600 float u4, float v4)
601{
602 const uint32_t vertsPerQuad = 4;
603 const uint32_t floatsPerVert = 5;
604 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
605
606 // Cull things that are off the screen
607 float width = (float)mRSC->getWidth();
608 float height = (float)mRSC->getHeight();
609
610 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
611 return;
612 }
613
614 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
615 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
616 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
617 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
618
619 (*currentPos++) = x1;
620 (*currentPos++) = y1;
621 (*currentPos++) = z1;
622 (*currentPos++) = u1;
623 (*currentPos++) = v1;
624
625 (*currentPos++) = x2;
626 (*currentPos++) = y2;
627 (*currentPos++) = z2;
628 (*currentPos++) = u2;
629 (*currentPos++) = v2;
630
631 (*currentPos++) = x3;
632 (*currentPos++) = y3;
633 (*currentPos++) = z3;
634 (*currentPos++) = u3;
635 (*currentPos++) = v3;
636
637 (*currentPos++) = x4;
638 (*currentPos++) = y4;
639 (*currentPos++) = z4;
640 (*currentPos++) = u4;
641 (*currentPos++) = v4;
642
643 mCurrentQuadIndex ++;
644
645 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
646 issueDrawCommand();
647 mCurrentQuadIndex = 0;
648 }
649}
650
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700651uint32_t FontState::getRemainingCacheCapacity() {
652 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700653 uint32_t totalPixels = 0;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700654 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
655 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
656 totalPixels += mCacheLines[i]->mMaxWidth;
657 }
658 remainingCapacity = (remainingCapacity * 100) / totalPixels;
659 return remainingCapacity;
660}
661
662void FontState::precacheLatin(Font *font) {
663 // Remaining capacity is measured in %
664 uint32_t remainingCapacity = getRemainingCacheCapacity();
665 uint32_t precacheIdx = 0;
666 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
667 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
668 remainingCapacity = getRemainingCacheCapacity();
669 precacheIdx ++;
670 }
671}
672
673
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700674void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
675{
676 checkInit();
677
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700678 // Render code here
679 Font *currentFont = mRSC->getFont();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700680 if(!currentFont) {
681 if(!mDefault.get()) {
682 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
683 }
684 currentFont = mDefault.get();
685 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700686 if(!currentFont) {
687 LOGE("Unable to initialize any fonts");
688 return;
689 }
690
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700691 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
692
693 if(mCurrentQuadIndex != 0) {
694 issueDrawCommand();
695 mCurrentQuadIndex = 0;
696 }
697}
698
699void FontState::renderText(const char *text, int x, int y)
700{
701 size_t textLen = strlen(text);
702 renderText(text, textLen, 0, -1, x, y);
703}
704
705void FontState::renderText(Allocation *alloc, int x, int y)
706{
707 if(!alloc) {
708 return;
709 }
710
711 const char *text = (const char *)alloc->getPtr();
712 size_t allocSize = alloc->getType()->getSizeBytes();
713 renderText(text, allocSize, 0, -1, x, y);
714}
715
716void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
717{
718 if(!alloc) {
719 return;
720 }
721
722 const char *text = (const char *)alloc->getPtr();
723 size_t allocSize = alloc->getType()->getSizeBytes();
724 renderText(text, allocSize, start, len, x, y);
725}
726
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700727void FontState::setFontColor(float r, float g, float b, float a) {
728 mFontColor[0] = r;
729 mFontColor[1] = g;
730 mFontColor[2] = b;
731 mFontColor[3] = a;
732 mFontColorDirty = true;
733}
734
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700735void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
736 *r = mFontColor[0];
737 *g = mFontColor[1];
738 *b = mFontColor[2];
739 *a = mFontColor[3];
740}
741
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700742void FontState::deinit(Context *rsc)
743{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700744 mInitialized = false;
745
746 mIndexBuffer.clear();
747 mVertexArray.clear();
748
749 mFontShaderF.clear();
750 mFontSampler.clear();
751 mFontProgramStore.clear();
752
753 mTextTexture.clear();
754 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
755 delete mCacheLines[i];
756 }
757 mCacheLines.clear();
758
759 mDefault.clear();
760
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700761 Vector<Font*> fontsToDereference = mActiveFonts;
762 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
763 fontsToDereference[i]->zeroUserRef();
764 }
765
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700766 if(mLibrary) {
767 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700768 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700769 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700770}
771
772namespace android {
773namespace renderscript {
774
775RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
776{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700777 Font *newFont = Font::create(rsc, name, fontSize, dpi);
778 if(newFont) {
779 newFont->incUserRef();
780 }
781 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700782}
783
784} // renderscript
785} // android