blob: d1346fc01dc8dfcb4f05bdeb17cd586aaf686ed1 [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
133 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
134
135 if(cachedGlyph == NULL) {
136 cachedGlyph = cacheGlyph((uint32_t)utfChar);
137 }
138 // Is the glyph still in texture cache?
139 if(!cachedGlyph->mIsValid) {
140 updateGlyphCache(cachedGlyph);
141 }
142
143 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
144 if(cachedGlyph->mIsValid) {
145 drawCachedGlyph(cachedGlyph, penX, penY);
146 }
147
148 penX += (cachedGlyph->mAdvance.x >> 6);
149
150 // If we were given a specific number of glyphs, decrement
151 if(numGlyphs > 0) {
152 glyphsLeft --;
153 }
154 }
155}
156
157void Font::updateGlyphCache(CachedGlyphInfo *glyph)
158{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700159 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
160 if(error) {
161 LOGE("Couldn't load glyph.");
162 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700163 }
164
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700165 glyph->mAdvance = mFace->glyph->advance;
166 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
167 glyph->mBitmapTop = mFace->glyph->bitmap_top;
168
169 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
170
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700171 // Now copy the bitmap into the cache texture
172 uint32_t startX = 0;
173 uint32_t startY = 0;
174
175 // Let the font state figure out where to put the bitmap
176 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700177 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700178
179 if(!glyph->mIsValid) {
180 return;
181 }
182
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700183 uint32_t endX = startX + bitmap->width;
184 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700185
186 glyph->mBitmapMinX = startX;
187 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700188 glyph->mBitmapWidth = bitmap->width;
189 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700190
191 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
192 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
193
194 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
195 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
196 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
197 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
198}
199
200Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
201{
202 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
203 mCachedGlyphs.add(glyph, newGlyph);
204
205 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
206 newGlyph->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700207
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700208 updateGlyphCache(newGlyph);
209
210 return newGlyph;
211}
212
213Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
214{
215 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
216
217 for(uint32_t i = 0; i < activeFonts.size(); i ++) {
218 Font *ithFont = activeFonts[i];
219 if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700220 return ithFont;
221 }
222 }
223
224 Font *newFont = new Font(rsc);
225 bool isInitialized = newFont->init(name, fontSize, dpi);
226 if(isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700227 activeFonts.push(newFont);
228 return newFont;
229 }
230
231 delete newFont;
232 return NULL;
233
234}
235
236Font::~Font()
237{
238 if(mFace) {
239 FT_Done_Face(mFace);
240 }
241
242 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
243 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
244 mRSC->mStateFont.mActiveFonts.removeAt(ct);
245 break;
246 }
247 }
248
249 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
250 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700251 delete glyph;
252 }
253}
254
255FontState::FontState()
256{
257 mInitialized = false;
258 mMaxNumberOfQuads = 1024;
259 mCurrentQuadIndex = 0;
260 mRSC = NULL;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700261 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700262}
263
264FontState::~FontState()
265{
266 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
267 delete mCacheLines[i];
268 }
269
270 rsAssert(!mActiveFonts.size());
271}
272
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700273FT_Library FontState::getLib()
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700274{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700275 if(!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700276 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700277 if(error) {
278 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700279 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700280 }
281 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700282
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700283 return mLibrary;
284}
285
286void FontState::init(Context *rsc)
287{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700288 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700289}
290
291void FontState::flushAllAndInvalidate()
292{
293 if(mCurrentQuadIndex != 0) {
294 issueDrawCommand();
295 mCurrentQuadIndex = 0;
296 }
297 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
298 mActiveFonts[i]->invalidateTextureCache();
299 }
300 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
301 mCacheLines[i]->mCurrentCol = 0;
302 }
303}
304
305bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
306{
307 // If the glyph is too tall, don't cache it
308 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
309 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
310 return false;
311 }
312
313 // Now copy the bitmap into the cache texture
314 uint32_t startX = 0;
315 uint32_t startY = 0;
316
317 bool bitmapFit = false;
318 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
319 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
320 if(bitmapFit) {
321 break;
322 }
323 }
324
325 // If the new glyph didn't fit, flush the state so far and invalidate everything
326 if(!bitmapFit) {
327 flushAllAndInvalidate();
328
329 // Try to fit it again
330 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
331 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
332 if(bitmapFit) {
333 break;
334 }
335 }
336
337 // if we still don't fit, something is wrong and we shouldn't draw
338 if(!bitmapFit) {
339 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
340 return false;
341 }
342 }
343
344 *retOriginX = startX;
345 *retOriginY = startY;
346
347 uint32_t endX = startX + bitmap->width;
348 uint32_t endY = startY + bitmap->rows;
349
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700350 uint32_t cacheWidth = getCacheTextureType()->getDimX();
351
352 unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
353 unsigned char *bitmapBuffer = bitmap->buffer;
354
355 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
356 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
357 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
358 unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
359 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
360 }
361 }
362
363 // This will dirty the texture and the shader so next time
364 // we draw it will upload the data
365 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
366 mFontShaderF->bindTexture(0, mTextTexture.get());
367
368 // Some debug code
369 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
370 LOGE("Cache Line: H: %u Empty Space: %f",
371 mCacheLines[i]->mMaxHeight,
372 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
373
374 }*/
375
376 return true;
377}
378
379void FontState::initRenderState()
380{
381 uint32_t tmp[5] = {
382 RS_TEX_ENV_MODE_REPLACE, 1,
383 RS_TEX_ENV_MODE_NONE, 0,
384 0
385 };
386 ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 5);
387 mFontShaderF.set(pf);
388 mFontShaderF->init(mRSC);
389
390 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
391 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
392 mFontSampler.set(sampler);
393 mFontShaderF->bindSampler(0, sampler);
394
395 ProgramStore *fontStore = new ProgramStore(mRSC);
396 mFontProgramStore.set(fontStore);
397 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
398 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
399 mFontProgramStore->setDitherEnable(false);
400 mFontProgramStore->setDepthMask(false);
401}
402
403void FontState::initTextTexture()
404{
405 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
406
407 // We will allocate a texture to initially hold 32 character bitmaps
408 Type *texType = new Type(mRSC);
409 texType->setElement(alphaElem);
410 texType->setDimX(1024);
411 texType->setDimY(256);
412 texType->compute();
413
414 Allocation *cacheAlloc = new Allocation(mRSC, texType);
415 mTextTexture.set(cacheAlloc);
416 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
417
418 // Split up our cache texture into lines of certain widths
419 int nextLine = 0;
420 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
421 nextLine += mCacheLines.top()->mMaxHeight;
422 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
423 nextLine += mCacheLines.top()->mMaxHeight;
424 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
425 nextLine += mCacheLines.top()->mMaxHeight;
426 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
427 nextLine += mCacheLines.top()->mMaxHeight;
428 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
429 nextLine += mCacheLines.top()->mMaxHeight;
430 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
431}
432
433// Avoid having to reallocate memory and render quad by quad
434void FontState::initVertexArrayBuffers()
435{
436 // Now lets write index data
437 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
438 Type *indexType = new Type(mRSC);
439 uint32_t numIndicies = mMaxNumberOfQuads * 6;
440 indexType->setDimX(numIndicies);
441 indexType->setElement(indexElem);
442 indexType->compute();
443
444 Allocation *indexAlloc = new Allocation(mRSC, indexType);
445 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
446
447 // Four verts, two triangles , six indices per quad
448 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
449 int i6 = i * 6;
450 int i4 = i * 4;
451
452 indexPtr[i6 + 0] = i4 + 0;
453 indexPtr[i6 + 1] = i4 + 1;
454 indexPtr[i6 + 2] = i4 + 2;
455
456 indexPtr[i6 + 3] = i4 + 0;
457 indexPtr[i6 + 4] = i4 + 2;
458 indexPtr[i6 + 5] = i4 + 3;
459 }
460
461 indexAlloc->deferedUploadToBufferObject(mRSC);
462 mIndexBuffer.set(indexAlloc);
463
464 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
465 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
466
467 const Element *elemArray[2];
468 elemArray[0] = posElem;
469 elemArray[1] = texElem;
470
471 String8 posName("position");
472 String8 texName("texture0");
473
474 const char *nameArray[2];
475 nameArray[0] = posName.string();
476 nameArray[1] = texName.string();
477 size_t lengths[2];
478 lengths[0] = posName.size();
479 lengths[1] = texName.size();
480
481 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths);
482
483 Type *vertexDataType = new Type(mRSC);
484 vertexDataType->setDimX(mMaxNumberOfQuads * 4);
485 vertexDataType->setElement(vertexDataElem);
486 vertexDataType->compute();
487
488 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
489 mTextMeshPtr = (float*)vertexAlloc->getPtr();
490
491 mVertexArray.set(vertexAlloc);
492}
493
494// We don't want to allocate anything unless we actually draw text
495void FontState::checkInit()
496{
497 if(mInitialized) {
498 return;
499 }
500
501 initTextTexture();
502 initRenderState();
503
504 initVertexArrayBuffers();
505
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700506 mInitialized = true;
507}
508
509void FontState::issueDrawCommand() {
510
511 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
512 mRSC->setVertex(mRSC->getDefaultProgramVertex());
513
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700514 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
515 mRSC->setRaster(mRSC->getDefaultProgramRaster());
516
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700517 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
518 mRSC->setFragment(mFontShaderF.get());
519
520 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
521 mRSC->setFragmentStore(mFontProgramStore.get());
522
523 if (!mRSC->setupCheck()) {
524 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700525 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700526 mRSC->setFragment((ProgramFragment *)tmpF.get());
527 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
528 return;
529 }
530
531 float *vtx = (float*)mVertexArray->getPtr();
532 float *tex = vtx + 3;
533
534 VertexArray va;
535 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
536 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
537 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
538
539 mIndexBuffer->uploadCheck(mRSC);
540 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
541 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
542
543 // Reset the state
544 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700545 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700546 mRSC->setFragment((ProgramFragment *)tmpF.get());
547 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
548}
549
550void FontState::appendMeshQuad(float x1, float y1, float z1,
551 float u1, float v1,
552 float x2, float y2, float z2,
553 float u2, float v2,
554 float x3, float y3, float z3,
555 float u3, float v3,
556 float x4, float y4, float z4,
557 float u4, float v4)
558{
559 const uint32_t vertsPerQuad = 4;
560 const uint32_t floatsPerVert = 5;
561 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
562
563 // Cull things that are off the screen
564 float width = (float)mRSC->getWidth();
565 float height = (float)mRSC->getHeight();
566
567 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
568 return;
569 }
570
571 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
572 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
573 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
574 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
575
576 (*currentPos++) = x1;
577 (*currentPos++) = y1;
578 (*currentPos++) = z1;
579 (*currentPos++) = u1;
580 (*currentPos++) = v1;
581
582 (*currentPos++) = x2;
583 (*currentPos++) = y2;
584 (*currentPos++) = z2;
585 (*currentPos++) = u2;
586 (*currentPos++) = v2;
587
588 (*currentPos++) = x3;
589 (*currentPos++) = y3;
590 (*currentPos++) = z3;
591 (*currentPos++) = u3;
592 (*currentPos++) = v3;
593
594 (*currentPos++) = x4;
595 (*currentPos++) = y4;
596 (*currentPos++) = z4;
597 (*currentPos++) = u4;
598 (*currentPos++) = v4;
599
600 mCurrentQuadIndex ++;
601
602 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
603 issueDrawCommand();
604 mCurrentQuadIndex = 0;
605 }
606}
607
608void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
609{
610 checkInit();
611
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700612 //String8 text8(text);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700613
614 // Render code here
615 Font *currentFont = mRSC->getFont();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700616 if(!currentFont) {
617 if(!mDefault.get()) {
618 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
619 }
620 currentFont = mDefault.get();
621 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700622 if(!currentFont) {
623 LOGE("Unable to initialize any fonts");
624 return;
625 }
626
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700627 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
628
629 if(mCurrentQuadIndex != 0) {
630 issueDrawCommand();
631 mCurrentQuadIndex = 0;
632 }
633}
634
635void FontState::renderText(const char *text, int x, int y)
636{
637 size_t textLen = strlen(text);
638 renderText(text, textLen, 0, -1, x, y);
639}
640
641void FontState::renderText(Allocation *alloc, int x, int y)
642{
643 if(!alloc) {
644 return;
645 }
646
647 const char *text = (const char *)alloc->getPtr();
648 size_t allocSize = alloc->getType()->getSizeBytes();
649 renderText(text, allocSize, 0, -1, x, y);
650}
651
652void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
653{
654 if(!alloc) {
655 return;
656 }
657
658 const char *text = (const char *)alloc->getPtr();
659 size_t allocSize = alloc->getType()->getSizeBytes();
660 renderText(text, allocSize, start, len, x, y);
661}
662
663void FontState::deinit(Context *rsc)
664{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700665 mInitialized = false;
666
667 mIndexBuffer.clear();
668 mVertexArray.clear();
669
670 mFontShaderF.clear();
671 mFontSampler.clear();
672 mFontProgramStore.clear();
673
674 mTextTexture.clear();
675 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
676 delete mCacheLines[i];
677 }
678 mCacheLines.clear();
679
680 mDefault.clear();
681
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700682 Vector<Font*> fontsToDereference = mActiveFonts;
683 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
684 fontsToDereference[i]->zeroUserRef();
685 }
686
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700687 if(mLibrary) {
688 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700689 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700690 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700691}
692
693namespace android {
694namespace renderscript {
695
696RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
697{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700698 Font *newFont = Font::create(rsc, name, fontSize, dpi);
699 if(newFont) {
700 newFont->incUserRef();
701 }
702 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700703}
704
705} // renderscript
706} // android