blob: 1ef9c93388030864f8f3d4a50cadd75ddfc3c591 [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{
221 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
222
223 for(uint32_t i = 0; i < activeFonts.size(); i ++) {
224 Font *ithFont = activeFonts[i];
225 if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700226 return ithFont;
227 }
228 }
229
230 Font *newFont = new Font(rsc);
231 bool isInitialized = newFont->init(name, fontSize, dpi);
232 if(isInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700233 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700234 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700235 return newFont;
236 }
237
238 delete newFont;
239 return NULL;
240
241}
242
243Font::~Font()
244{
245 if(mFace) {
246 FT_Done_Face(mFace);
247 }
248
249 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
250 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
251 mRSC->mStateFont.mActiveFonts.removeAt(ct);
252 break;
253 }
254 }
255
256 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
257 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700258 delete glyph;
259 }
260}
261
262FontState::FontState()
263{
264 mInitialized = false;
265 mMaxNumberOfQuads = 1024;
266 mCurrentQuadIndex = 0;
267 mRSC = NULL;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700268 mLibrary = NULL;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700269 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700270}
271
272FontState::~FontState()
273{
274 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
275 delete mCacheLines[i];
276 }
277
278 rsAssert(!mActiveFonts.size());
279}
280
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700281FT_Library FontState::getLib()
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700282{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700283 if(!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700284 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700285 if(error) {
286 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700287 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700288 }
289 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700290
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700291 return mLibrary;
292}
293
294void FontState::init(Context *rsc)
295{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700296 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700297}
298
299void FontState::flushAllAndInvalidate()
300{
301 if(mCurrentQuadIndex != 0) {
302 issueDrawCommand();
303 mCurrentQuadIndex = 0;
304 }
305 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
306 mActiveFonts[i]->invalidateTextureCache();
307 }
308 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
309 mCacheLines[i]->mCurrentCol = 0;
310 }
311}
312
313bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
314{
315 // If the glyph is too tall, don't cache it
316 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
317 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
318 return false;
319 }
320
321 // Now copy the bitmap into the cache texture
322 uint32_t startX = 0;
323 uint32_t startY = 0;
324
325 bool bitmapFit = false;
326 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
327 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
328 if(bitmapFit) {
329 break;
330 }
331 }
332
333 // If the new glyph didn't fit, flush the state so far and invalidate everything
334 if(!bitmapFit) {
335 flushAllAndInvalidate();
336
337 // Try to fit it again
338 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
339 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
340 if(bitmapFit) {
341 break;
342 }
343 }
344
345 // if we still don't fit, something is wrong and we shouldn't draw
346 if(!bitmapFit) {
347 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
348 return false;
349 }
350 }
351
352 *retOriginX = startX;
353 *retOriginY = startY;
354
355 uint32_t endX = startX + bitmap->width;
356 uint32_t endY = startY + bitmap->rows;
357
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700358 uint32_t cacheWidth = getCacheTextureType()->getDimX();
359
360 unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
361 unsigned char *bitmapBuffer = bitmap->buffer;
362
363 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
364 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
365 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
366 unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
367 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
368 }
369 }
370
371 // This will dirty the texture and the shader so next time
372 // we draw it will upload the data
373 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
374 mFontShaderF->bindTexture(0, mTextTexture.get());
375
376 // Some debug code
377 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
378 LOGE("Cache Line: H: %u Empty Space: %f",
379 mCacheLines[i]->mMaxHeight,
380 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
381
382 }*/
383
384 return true;
385}
386
387void FontState::initRenderState()
388{
Jason Sams442a6472010-08-04 17:50:20 -0700389 uint32_t tmp[] = {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700390 RS_TEX_ENV_MODE_REPLACE, 1,
391 RS_TEX_ENV_MODE_NONE, 0,
Jason Sams442a6472010-08-04 17:50:20 -0700392 0, 0
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700393 };
Jason Sams442a6472010-08-04 17:50:20 -0700394 ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 6);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700395 mFontShaderF.set(pf);
396 mFontShaderF->init(mRSC);
397
398 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
399 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
400 mFontSampler.set(sampler);
401 mFontShaderF->bindSampler(0, sampler);
402
403 ProgramStore *fontStore = new ProgramStore(mRSC);
404 mFontProgramStore.set(fontStore);
405 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
406 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
407 mFontProgramStore->setDitherEnable(false);
408 mFontProgramStore->setDepthMask(false);
409}
410
411void FontState::initTextTexture()
412{
413 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
414
415 // We will allocate a texture to initially hold 32 character bitmaps
416 Type *texType = new Type(mRSC);
417 texType->setElement(alphaElem);
418 texType->setDimX(1024);
419 texType->setDimY(256);
420 texType->compute();
421
422 Allocation *cacheAlloc = new Allocation(mRSC, texType);
423 mTextTexture.set(cacheAlloc);
424 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
425
426 // Split up our cache texture into lines of certain widths
427 int nextLine = 0;
428 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
429 nextLine += mCacheLines.top()->mMaxHeight;
430 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
431 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700432 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
433 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700434 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
435 nextLine += mCacheLines.top()->mMaxHeight;
436 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
437 nextLine += mCacheLines.top()->mMaxHeight;
438 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
439 nextLine += mCacheLines.top()->mMaxHeight;
440 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
441}
442
443// Avoid having to reallocate memory and render quad by quad
444void FontState::initVertexArrayBuffers()
445{
446 // Now lets write index data
447 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
448 Type *indexType = new Type(mRSC);
449 uint32_t numIndicies = mMaxNumberOfQuads * 6;
450 indexType->setDimX(numIndicies);
451 indexType->setElement(indexElem);
452 indexType->compute();
453
454 Allocation *indexAlloc = new Allocation(mRSC, indexType);
455 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
456
457 // Four verts, two triangles , six indices per quad
458 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
459 int i6 = i * 6;
460 int i4 = i * 4;
461
462 indexPtr[i6 + 0] = i4 + 0;
463 indexPtr[i6 + 1] = i4 + 1;
464 indexPtr[i6 + 2] = i4 + 2;
465
466 indexPtr[i6 + 3] = i4 + 0;
467 indexPtr[i6 + 4] = i4 + 2;
468 indexPtr[i6 + 5] = i4 + 3;
469 }
470
471 indexAlloc->deferedUploadToBufferObject(mRSC);
472 mIndexBuffer.set(indexAlloc);
473
474 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
475 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
476
477 const Element *elemArray[2];
478 elemArray[0] = posElem;
479 elemArray[1] = texElem;
480
481 String8 posName("position");
482 String8 texName("texture0");
483
484 const char *nameArray[2];
485 nameArray[0] = posName.string();
486 nameArray[1] = texName.string();
487 size_t lengths[2];
488 lengths[0] = posName.size();
489 lengths[1] = texName.size();
490
491 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths);
492
493 Type *vertexDataType = new Type(mRSC);
494 vertexDataType->setDimX(mMaxNumberOfQuads * 4);
495 vertexDataType->setElement(vertexDataElem);
496 vertexDataType->compute();
497
498 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
499 mTextMeshPtr = (float*)vertexAlloc->getPtr();
500
501 mVertexArray.set(vertexAlloc);
502}
503
504// We don't want to allocate anything unless we actually draw text
505void FontState::checkInit()
506{
507 if(mInitialized) {
508 return;
509 }
510
511 initTextTexture();
512 initRenderState();
513
514 initVertexArrayBuffers();
515
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700516 mInitialized = true;
517}
518
519void FontState::issueDrawCommand() {
520
521 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
522 mRSC->setVertex(mRSC->getDefaultProgramVertex());
523
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700524 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
525 mRSC->setRaster(mRSC->getDefaultProgramRaster());
526
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700527 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
528 mRSC->setFragment(mFontShaderF.get());
529
530 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
531 mRSC->setFragmentStore(mFontProgramStore.get());
532
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700533 if(mFontColorDirty) {
534 mFontShaderF->setConstantColor(mFontColor[0], mFontColor[1], mFontColor[2], mFontColor[3]);
535 mFontColorDirty = false;
536 }
537
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700538 if (!mRSC->setupCheck()) {
539 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700540 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700541 mRSC->setFragment((ProgramFragment *)tmpF.get());
542 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
543 return;
544 }
545
546 float *vtx = (float*)mVertexArray->getPtr();
547 float *tex = vtx + 3;
548
549 VertexArray va;
550 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
551 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
552 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
553
554 mIndexBuffer->uploadCheck(mRSC);
555 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
556 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
557
558 // Reset the state
559 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700560 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700561 mRSC->setFragment((ProgramFragment *)tmpF.get());
562 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
563}
564
565void FontState::appendMeshQuad(float x1, float y1, float z1,
566 float u1, float v1,
567 float x2, float y2, float z2,
568 float u2, float v2,
569 float x3, float y3, float z3,
570 float u3, float v3,
571 float x4, float y4, float z4,
572 float u4, float v4)
573{
574 const uint32_t vertsPerQuad = 4;
575 const uint32_t floatsPerVert = 5;
576 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
577
578 // Cull things that are off the screen
579 float width = (float)mRSC->getWidth();
580 float height = (float)mRSC->getHeight();
581
582 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
583 return;
584 }
585
586 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
587 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
588 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
589 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
590
591 (*currentPos++) = x1;
592 (*currentPos++) = y1;
593 (*currentPos++) = z1;
594 (*currentPos++) = u1;
595 (*currentPos++) = v1;
596
597 (*currentPos++) = x2;
598 (*currentPos++) = y2;
599 (*currentPos++) = z2;
600 (*currentPos++) = u2;
601 (*currentPos++) = v2;
602
603 (*currentPos++) = x3;
604 (*currentPos++) = y3;
605 (*currentPos++) = z3;
606 (*currentPos++) = u3;
607 (*currentPos++) = v3;
608
609 (*currentPos++) = x4;
610 (*currentPos++) = y4;
611 (*currentPos++) = z4;
612 (*currentPos++) = u4;
613 (*currentPos++) = v4;
614
615 mCurrentQuadIndex ++;
616
617 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
618 issueDrawCommand();
619 mCurrentQuadIndex = 0;
620 }
621}
622
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700623uint32_t FontState::getRemainingCacheCapacity() {
624 uint32_t remainingCapacity = 0;
625 float totalPixels = 0;
626 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
627 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
628 totalPixels += mCacheLines[i]->mMaxWidth;
629 }
630 remainingCapacity = (remainingCapacity * 100) / totalPixels;
631 return remainingCapacity;
632}
633
634void FontState::precacheLatin(Font *font) {
635 // Remaining capacity is measured in %
636 uint32_t remainingCapacity = getRemainingCacheCapacity();
637 uint32_t precacheIdx = 0;
638 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
639 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
640 remainingCapacity = getRemainingCacheCapacity();
641 precacheIdx ++;
642 }
643}
644
645
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700646void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
647{
648 checkInit();
649
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700650 // Render code here
651 Font *currentFont = mRSC->getFont();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700652 if(!currentFont) {
653 if(!mDefault.get()) {
654 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
655 }
656 currentFont = mDefault.get();
657 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700658 if(!currentFont) {
659 LOGE("Unable to initialize any fonts");
660 return;
661 }
662
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700663 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
664
665 if(mCurrentQuadIndex != 0) {
666 issueDrawCommand();
667 mCurrentQuadIndex = 0;
668 }
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700669
670 // We store a string with letters in a rough frequency of occurrence
671 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
672 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
673 mLatinPrecache += String8(",.?!()-+@;:`'");
674 mLatinPrecache += String8("0123456789");
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700675}
676
677void FontState::renderText(const char *text, int x, int y)
678{
679 size_t textLen = strlen(text);
680 renderText(text, textLen, 0, -1, x, y);
681}
682
683void FontState::renderText(Allocation *alloc, int x, int y)
684{
685 if(!alloc) {
686 return;
687 }
688
689 const char *text = (const char *)alloc->getPtr();
690 size_t allocSize = alloc->getType()->getSizeBytes();
691 renderText(text, allocSize, 0, -1, x, y);
692}
693
694void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
695{
696 if(!alloc) {
697 return;
698 }
699
700 const char *text = (const char *)alloc->getPtr();
701 size_t allocSize = alloc->getType()->getSizeBytes();
702 renderText(text, allocSize, start, len, x, y);
703}
704
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700705void FontState::setFontColor(float r, float g, float b, float a) {
706 mFontColor[0] = r;
707 mFontColor[1] = g;
708 mFontColor[2] = b;
709 mFontColor[3] = a;
710 mFontColorDirty = true;
711}
712
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700713void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
714 *r = mFontColor[0];
715 *g = mFontColor[1];
716 *b = mFontColor[2];
717 *a = mFontColor[3];
718}
719
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700720void FontState::deinit(Context *rsc)
721{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700722 mInitialized = false;
723
724 mIndexBuffer.clear();
725 mVertexArray.clear();
726
727 mFontShaderF.clear();
728 mFontSampler.clear();
729 mFontProgramStore.clear();
730
731 mTextTexture.clear();
732 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
733 delete mCacheLines[i];
734 }
735 mCacheLines.clear();
736
737 mDefault.clear();
738
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700739 Vector<Font*> fontsToDereference = mActiveFonts;
740 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
741 fontsToDereference[i]->zeroUserRef();
742 }
743
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700744 if(mLibrary) {
745 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700746 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700747 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700748}
749
750namespace android {
751namespace renderscript {
752
753RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
754{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700755 Font *newFont = Font::create(rsc, name, fontSize, dpi);
756 if(newFont) {
757 newFont->incUserRef();
758 }
759 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700760}
761
762} // renderscript
763} // android