blob: 5889bfb23976af32c146e884fa55c945f4fd34cf [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"
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 Sakhartchouk071508d2010-06-30 12:49:27 -070038 mAllocFile = __FILE__;
39 mAllocLine = __LINE__;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070040 mInitialized = false;
41 mHasKerning = false;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -070042 mFace = NULL;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -070057 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk94bbccc2010-08-17 11:09:49 -0700133 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk94bbccc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700163void Font::updateGlyphCache(CachedGlyphInfo *glyph)
164{
Alex Sakhartchouk071508d2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700169 }
170
Alex Sakhartchouk071508d2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700183 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700184
185 if(!glyph->mIsValid) {
186 return;
187 }
188
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700189 uint32_t endX = startX + bitmap->width;
190 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700191
192 glyph->mBitmapMinX = startX;
193 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700194 glyph->mBitmapWidth = bitmap->width;
195 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700213
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk27f50522010-08-18 15:46:43 -0700221 rsc->mStateFont.checkInit();
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700234 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700235 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-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 Sakhartchoukb6b34892010-06-30 16:53:43 -0700269 mLibrary = NULL;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700270 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700282FT_Library FontState::getLib()
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700283{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700284 if(!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700285 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700286 if(error) {
287 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700288 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700289 }
290 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700291
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700292 return mLibrary;
293}
294
295void FontState::init(Context *rsc)
296{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700297 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-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 Sams442a6472010-08-04 17:50:20 -0700390 uint32_t tmp[] = {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700391 RS_TEX_ENV_MODE_REPLACE, 1,
392 RS_TEX_ENV_MODE_NONE, 0,
Jason Sams442a6472010-08-04 17:50:20 -0700393 0, 0
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700394 };
Jason Sams442a6472010-08-04 17:50:20 -0700395 ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 6);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk94bbccc2010-08-17 11:09:49 -0700433 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
434 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-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();
Jason Sams70d4e502010-09-02 17:35:23 -0700491 uint32_t arraySizes[2] = {1, 1};
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700492
Jason Sams70d4e502010-09-02 17:35:23 -0700493 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700494
495 Type *vertexDataType = new Type(mRSC);
496 vertexDataType->setDimX(mMaxNumberOfQuads * 4);
497 vertexDataType->setElement(vertexDataElem);
498 vertexDataType->compute();
499
500 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
501 mTextMeshPtr = (float*)vertexAlloc->getPtr();
502
503 mVertexArray.set(vertexAlloc);
504}
505
506// We don't want to allocate anything unless we actually draw text
507void FontState::checkInit()
508{
509 if(mInitialized) {
510 return;
511 }
512
513 initTextTexture();
514 initRenderState();
515
516 initVertexArrayBuffers();
517
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700518 // We store a string with letters in a rough frequency of occurrence
519 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
520 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
521 mLatinPrecache += String8(",.?!()-+@;:`'");
522 mLatinPrecache += String8("0123456789");
523
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700524 mInitialized = true;
525}
526
527void FontState::issueDrawCommand() {
528
529 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
530 mRSC->setVertex(mRSC->getDefaultProgramVertex());
531
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700532 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
533 mRSC->setRaster(mRSC->getDefaultProgramRaster());
534
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700535 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
536 mRSC->setFragment(mFontShaderF.get());
537
538 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
539 mRSC->setFragmentStore(mFontProgramStore.get());
540
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700541 if(mFontColorDirty) {
542 mFontShaderF->setConstantColor(mFontColor[0], mFontColor[1], mFontColor[2], mFontColor[3]);
543 mFontColorDirty = false;
544 }
545
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700546 if (!mRSC->setupCheck()) {
547 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700548 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700549 mRSC->setFragment((ProgramFragment *)tmpF.get());
550 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
551 return;
552 }
553
554 float *vtx = (float*)mVertexArray->getPtr();
555 float *tex = vtx + 3;
556
557 VertexArray va;
558 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
559 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
560 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
561
562 mIndexBuffer->uploadCheck(mRSC);
563 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
564 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
565
566 // Reset the state
567 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700568 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700569 mRSC->setFragment((ProgramFragment *)tmpF.get());
570 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
571}
572
573void FontState::appendMeshQuad(float x1, float y1, float z1,
574 float u1, float v1,
575 float x2, float y2, float z2,
576 float u2, float v2,
577 float x3, float y3, float z3,
578 float u3, float v3,
579 float x4, float y4, float z4,
580 float u4, float v4)
581{
582 const uint32_t vertsPerQuad = 4;
583 const uint32_t floatsPerVert = 5;
584 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
585
586 // Cull things that are off the screen
587 float width = (float)mRSC->getWidth();
588 float height = (float)mRSC->getHeight();
589
590 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
591 return;
592 }
593
594 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
595 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
596 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
597 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
598
599 (*currentPos++) = x1;
600 (*currentPos++) = y1;
601 (*currentPos++) = z1;
602 (*currentPos++) = u1;
603 (*currentPos++) = v1;
604
605 (*currentPos++) = x2;
606 (*currentPos++) = y2;
607 (*currentPos++) = z2;
608 (*currentPos++) = u2;
609 (*currentPos++) = v2;
610
611 (*currentPos++) = x3;
612 (*currentPos++) = y3;
613 (*currentPos++) = z3;
614 (*currentPos++) = u3;
615 (*currentPos++) = v3;
616
617 (*currentPos++) = x4;
618 (*currentPos++) = y4;
619 (*currentPos++) = z4;
620 (*currentPos++) = u4;
621 (*currentPos++) = v4;
622
623 mCurrentQuadIndex ++;
624
625 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
626 issueDrawCommand();
627 mCurrentQuadIndex = 0;
628 }
629}
630
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700631uint32_t FontState::getRemainingCacheCapacity() {
632 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700633 uint32_t totalPixels = 0;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700634 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
635 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
636 totalPixels += mCacheLines[i]->mMaxWidth;
637 }
638 remainingCapacity = (remainingCapacity * 100) / totalPixels;
639 return remainingCapacity;
640}
641
642void FontState::precacheLatin(Font *font) {
643 // Remaining capacity is measured in %
644 uint32_t remainingCapacity = getRemainingCacheCapacity();
645 uint32_t precacheIdx = 0;
646 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
647 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
648 remainingCapacity = getRemainingCacheCapacity();
649 precacheIdx ++;
650 }
651}
652
653
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700654void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
655{
656 checkInit();
657
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700658 // Render code here
659 Font *currentFont = mRSC->getFont();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700660 if(!currentFont) {
661 if(!mDefault.get()) {
662 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
663 }
664 currentFont = mDefault.get();
665 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700666 if(!currentFont) {
667 LOGE("Unable to initialize any fonts");
668 return;
669 }
670
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700671 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
672
673 if(mCurrentQuadIndex != 0) {
674 issueDrawCommand();
675 mCurrentQuadIndex = 0;
676 }
677}
678
679void FontState::renderText(const char *text, int x, int y)
680{
681 size_t textLen = strlen(text);
682 renderText(text, textLen, 0, -1, x, y);
683}
684
685void FontState::renderText(Allocation *alloc, int x, int y)
686{
687 if(!alloc) {
688 return;
689 }
690
691 const char *text = (const char *)alloc->getPtr();
692 size_t allocSize = alloc->getType()->getSizeBytes();
693 renderText(text, allocSize, 0, -1, x, y);
694}
695
696void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
697{
698 if(!alloc) {
699 return;
700 }
701
702 const char *text = (const char *)alloc->getPtr();
703 size_t allocSize = alloc->getType()->getSizeBytes();
704 renderText(text, allocSize, start, len, x, y);
705}
706
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700707void FontState::setFontColor(float r, float g, float b, float a) {
708 mFontColor[0] = r;
709 mFontColor[1] = g;
710 mFontColor[2] = b;
711 mFontColor[3] = a;
712 mFontColorDirty = true;
713}
714
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700715void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
716 *r = mFontColor[0];
717 *g = mFontColor[1];
718 *b = mFontColor[2];
719 *a = mFontColor[3];
720}
721
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700722void FontState::deinit(Context *rsc)
723{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700724 mInitialized = false;
725
726 mIndexBuffer.clear();
727 mVertexArray.clear();
728
729 mFontShaderF.clear();
730 mFontSampler.clear();
731 mFontProgramStore.clear();
732
733 mTextTexture.clear();
734 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
735 delete mCacheLines[i];
736 }
737 mCacheLines.clear();
738
739 mDefault.clear();
740
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700741 Vector<Font*> fontsToDereference = mActiveFonts;
742 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
743 fontsToDereference[i]->zeroUserRef();
744 }
745
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700746 if(mLibrary) {
747 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700748 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700749 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700750}
751
752namespace android {
753namespace renderscript {
754
755RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
756{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700757 Font *newFont = Font::create(rsc, name, fontSize, dpi);
758 if(newFont) {
759 newFont->incUserRef();
760 }
761 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700762}
763
764} // renderscript
765} // android