blob: 7661d499b84fa260282a9c95348887fae8f773f7 [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{
Jason Sams6445e522010-08-04 17:50:20 -0700390 uint32_t tmp[] = {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700391 RS_TEX_ENV_MODE_REPLACE, 1,
392 RS_TEX_ENV_MODE_NONE, 0,
Jason Sams6445e522010-08-04 17:50:20 -0700393 0, 0
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700394 };
Jason Sams6445e522010-08-04 17:50:20 -0700395 ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700396 mFontShaderF.set(pf);
397 mFontShaderF->init(mRSC);
398
399 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
400 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
401 mFontSampler.set(sampler);
402 mFontShaderF->bindSampler(0, sampler);
403
404 ProgramStore *fontStore = new ProgramStore(mRSC);
405 mFontProgramStore.set(fontStore);
406 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
407 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
408 mFontProgramStore->setDitherEnable(false);
409 mFontProgramStore->setDepthMask(false);
410}
411
412void FontState::initTextTexture()
413{
414 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
415
416 // We will allocate a texture to initially hold 32 character bitmaps
417 Type *texType = new Type(mRSC);
418 texType->setElement(alphaElem);
419 texType->setDimX(1024);
420 texType->setDimY(256);
421 texType->compute();
422
423 Allocation *cacheAlloc = new Allocation(mRSC, texType);
424 mTextTexture.set(cacheAlloc);
425 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
426
427 // Split up our cache texture into lines of certain widths
428 int nextLine = 0;
429 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
430 nextLine += mCacheLines.top()->mMaxHeight;
431 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
432 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700433 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
434 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700435 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
436 nextLine += mCacheLines.top()->mMaxHeight;
437 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
438 nextLine += mCacheLines.top()->mMaxHeight;
439 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
440 nextLine += mCacheLines.top()->mMaxHeight;
441 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
442}
443
444// Avoid having to reallocate memory and render quad by quad
445void FontState::initVertexArrayBuffers()
446{
447 // Now lets write index data
448 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
449 Type *indexType = new Type(mRSC);
450 uint32_t numIndicies = mMaxNumberOfQuads * 6;
451 indexType->setDimX(numIndicies);
452 indexType->setElement(indexElem);
453 indexType->compute();
454
455 Allocation *indexAlloc = new Allocation(mRSC, indexType);
456 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
457
458 // Four verts, two triangles , six indices per quad
459 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
460 int i6 = i * 6;
461 int i4 = i * 4;
462
463 indexPtr[i6 + 0] = i4 + 0;
464 indexPtr[i6 + 1] = i4 + 1;
465 indexPtr[i6 + 2] = i4 + 2;
466
467 indexPtr[i6 + 3] = i4 + 0;
468 indexPtr[i6 + 4] = i4 + 2;
469 indexPtr[i6 + 5] = i4 + 3;
470 }
471
472 indexAlloc->deferedUploadToBufferObject(mRSC);
473 mIndexBuffer.set(indexAlloc);
474
475 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
476 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
477
478 const Element *elemArray[2];
479 elemArray[0] = posElem;
480 elemArray[1] = texElem;
481
482 String8 posName("position");
483 String8 texName("texture0");
484
485 const char *nameArray[2];
486 nameArray[0] = posName.string();
487 nameArray[1] = texName.string();
488 size_t lengths[2];
489 lengths[0] = posName.size();
490 lengths[1] = texName.size();
491
492 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths);
493
494 Type *vertexDataType = new Type(mRSC);
495 vertexDataType->setDimX(mMaxNumberOfQuads * 4);
496 vertexDataType->setElement(vertexDataElem);
497 vertexDataType->compute();
498
499 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
500 mTextMeshPtr = (float*)vertexAlloc->getPtr();
501
502 mVertexArray.set(vertexAlloc);
503}
504
505// We don't want to allocate anything unless we actually draw text
506void FontState::checkInit()
507{
508 if(mInitialized) {
509 return;
510 }
511
512 initTextTexture();
513 initRenderState();
514
515 initVertexArrayBuffers();
516
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700517 // We store a string with letters in a rough frequency of occurrence
518 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
519 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
520 mLatinPrecache += String8(",.?!()-+@;:`'");
521 mLatinPrecache += String8("0123456789");
522
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700523 mInitialized = true;
524}
525
526void FontState::issueDrawCommand() {
527
528 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
529 mRSC->setVertex(mRSC->getDefaultProgramVertex());
530
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700531 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
532 mRSC->setRaster(mRSC->getDefaultProgramRaster());
533
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700534 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
535 mRSC->setFragment(mFontShaderF.get());
536
537 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
538 mRSC->setFragmentStore(mFontProgramStore.get());
539
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700540 if(mFontColorDirty) {
541 mFontShaderF->setConstantColor(mFontColor[0], mFontColor[1], mFontColor[2], mFontColor[3]);
542 mFontColorDirty = false;
543 }
544
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700545 if (!mRSC->setupCheck()) {
546 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700547 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700548 mRSC->setFragment((ProgramFragment *)tmpF.get());
549 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
550 return;
551 }
552
553 float *vtx = (float*)mVertexArray->getPtr();
554 float *tex = vtx + 3;
555
556 VertexArray va;
557 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
558 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
559 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
560
561 mIndexBuffer->uploadCheck(mRSC);
562 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
563 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
564
565 // Reset the state
566 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700567 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700568 mRSC->setFragment((ProgramFragment *)tmpF.get());
569 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
570}
571
572void FontState::appendMeshQuad(float x1, float y1, float z1,
573 float u1, float v1,
574 float x2, float y2, float z2,
575 float u2, float v2,
576 float x3, float y3, float z3,
577 float u3, float v3,
578 float x4, float y4, float z4,
579 float u4, float v4)
580{
581 const uint32_t vertsPerQuad = 4;
582 const uint32_t floatsPerVert = 5;
583 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
584
585 // Cull things that are off the screen
586 float width = (float)mRSC->getWidth();
587 float height = (float)mRSC->getHeight();
588
589 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
590 return;
591 }
592
593 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
594 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
595 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
596 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
597
598 (*currentPos++) = x1;
599 (*currentPos++) = y1;
600 (*currentPos++) = z1;
601 (*currentPos++) = u1;
602 (*currentPos++) = v1;
603
604 (*currentPos++) = x2;
605 (*currentPos++) = y2;
606 (*currentPos++) = z2;
607 (*currentPos++) = u2;
608 (*currentPos++) = v2;
609
610 (*currentPos++) = x3;
611 (*currentPos++) = y3;
612 (*currentPos++) = z3;
613 (*currentPos++) = u3;
614 (*currentPos++) = v3;
615
616 (*currentPos++) = x4;
617 (*currentPos++) = y4;
618 (*currentPos++) = z4;
619 (*currentPos++) = u4;
620 (*currentPos++) = v4;
621
622 mCurrentQuadIndex ++;
623
624 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
625 issueDrawCommand();
626 mCurrentQuadIndex = 0;
627 }
628}
629
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700630uint32_t FontState::getRemainingCacheCapacity() {
631 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700632 uint32_t totalPixels = 0;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700633 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
634 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
635 totalPixels += mCacheLines[i]->mMaxWidth;
636 }
637 remainingCapacity = (remainingCapacity * 100) / totalPixels;
638 return remainingCapacity;
639}
640
641void FontState::precacheLatin(Font *font) {
642 // Remaining capacity is measured in %
643 uint32_t remainingCapacity = getRemainingCacheCapacity();
644 uint32_t precacheIdx = 0;
645 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
646 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
647 remainingCapacity = getRemainingCacheCapacity();
648 precacheIdx ++;
649 }
650}
651
652
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700653void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
654{
655 checkInit();
656
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700657 // Render code here
658 Font *currentFont = mRSC->getFont();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700659 if(!currentFont) {
660 if(!mDefault.get()) {
661 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
662 }
663 currentFont = mDefault.get();
664 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700665 if(!currentFont) {
666 LOGE("Unable to initialize any fonts");
667 return;
668 }
669
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700670 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
671
672 if(mCurrentQuadIndex != 0) {
673 issueDrawCommand();
674 mCurrentQuadIndex = 0;
675 }
676}
677
678void FontState::renderText(const char *text, int x, int y)
679{
680 size_t textLen = strlen(text);
681 renderText(text, textLen, 0, -1, x, y);
682}
683
684void FontState::renderText(Allocation *alloc, int x, int y)
685{
686 if(!alloc) {
687 return;
688 }
689
690 const char *text = (const char *)alloc->getPtr();
691 size_t allocSize = alloc->getType()->getSizeBytes();
692 renderText(text, allocSize, 0, -1, x, y);
693}
694
695void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
696{
697 if(!alloc) {
698 return;
699 }
700
701 const char *text = (const char *)alloc->getPtr();
702 size_t allocSize = alloc->getType()->getSizeBytes();
703 renderText(text, allocSize, start, len, x, y);
704}
705
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700706void FontState::setFontColor(float r, float g, float b, float a) {
707 mFontColor[0] = r;
708 mFontColor[1] = g;
709 mFontColor[2] = b;
710 mFontColor[3] = a;
711 mFontColorDirty = true;
712}
713
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700714void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
715 *r = mFontColor[0];
716 *g = mFontColor[1];
717 *b = mFontColor[2];
718 *a = mFontColor[3];
719}
720
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700721void FontState::deinit(Context *rsc)
722{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700723 mInitialized = false;
724
725 mIndexBuffer.clear();
726 mVertexArray.clear();
727
728 mFontShaderF.clear();
729 mFontSampler.clear();
730 mFontProgramStore.clear();
731
732 mTextTexture.clear();
733 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
734 delete mCacheLines[i];
735 }
736 mCacheLines.clear();
737
738 mDefault.clear();
739
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700740 Vector<Font*> fontsToDereference = mActiveFonts;
741 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
742 fontsToDereference[i]->zeroUserRef();
743 }
744
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700745 if(mLibrary) {
746 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700747 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700748 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700749}
750
751namespace android {
752namespace renderscript {
753
754RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
755{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700756 Font *newFont = Font::create(rsc, name, fontSize, dpi);
757 if(newFont) {
758 newFont->incUserRef();
759 }
760 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700761}
762
763} // renderscript
764} // android