blob: e58d8b18ec97879946f7f36f8271a62069a05b21 [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 Sakhartchouk9fc9f032010-08-04 14:45:48 -0700262 setFontColor(0.0f, 0.0f, 0.0f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700263}
264
265FontState::~FontState()
266{
267 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
268 delete mCacheLines[i];
269 }
270
271 rsAssert(!mActiveFonts.size());
272}
273
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700274FT_Library FontState::getLib()
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700275{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700276 if(!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700277 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700278 if(error) {
279 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700280 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700281 }
282 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700283
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700284 return mLibrary;
285}
286
287void FontState::init(Context *rsc)
288{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700289 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700290}
291
292void FontState::flushAllAndInvalidate()
293{
294 if(mCurrentQuadIndex != 0) {
295 issueDrawCommand();
296 mCurrentQuadIndex = 0;
297 }
298 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
299 mActiveFonts[i]->invalidateTextureCache();
300 }
301 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
302 mCacheLines[i]->mCurrentCol = 0;
303 }
304}
305
306bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
307{
308 // If the glyph is too tall, don't cache it
309 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
310 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
311 return false;
312 }
313
314 // Now copy the bitmap into the cache texture
315 uint32_t startX = 0;
316 uint32_t startY = 0;
317
318 bool bitmapFit = false;
319 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
320 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
321 if(bitmapFit) {
322 break;
323 }
324 }
325
326 // If the new glyph didn't fit, flush the state so far and invalidate everything
327 if(!bitmapFit) {
328 flushAllAndInvalidate();
329
330 // Try to fit it again
331 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
332 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
333 if(bitmapFit) {
334 break;
335 }
336 }
337
338 // if we still don't fit, something is wrong and we shouldn't draw
339 if(!bitmapFit) {
340 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
341 return false;
342 }
343 }
344
345 *retOriginX = startX;
346 *retOriginY = startY;
347
348 uint32_t endX = startX + bitmap->width;
349 uint32_t endY = startY + bitmap->rows;
350
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700351 uint32_t cacheWidth = getCacheTextureType()->getDimX();
352
353 unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
354 unsigned char *bitmapBuffer = bitmap->buffer;
355
356 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
357 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
358 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
359 unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
360 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
361 }
362 }
363
364 // This will dirty the texture and the shader so next time
365 // we draw it will upload the data
366 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
367 mFontShaderF->bindTexture(0, mTextTexture.get());
368
369 // Some debug code
370 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
371 LOGE("Cache Line: H: %u Empty Space: %f",
372 mCacheLines[i]->mMaxHeight,
373 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
374
375 }*/
376
377 return true;
378}
379
380void FontState::initRenderState()
381{
382 uint32_t tmp[5] = {
383 RS_TEX_ENV_MODE_REPLACE, 1,
384 RS_TEX_ENV_MODE_NONE, 0,
385 0
386 };
387 ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 5);
388 mFontShaderF.set(pf);
389 mFontShaderF->init(mRSC);
390
391 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
392 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
393 mFontSampler.set(sampler);
394 mFontShaderF->bindSampler(0, sampler);
395
396 ProgramStore *fontStore = new ProgramStore(mRSC);
397 mFontProgramStore.set(fontStore);
398 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
399 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
400 mFontProgramStore->setDitherEnable(false);
401 mFontProgramStore->setDepthMask(false);
402}
403
404void FontState::initTextTexture()
405{
406 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
407
408 // We will allocate a texture to initially hold 32 character bitmaps
409 Type *texType = new Type(mRSC);
410 texType->setElement(alphaElem);
411 texType->setDimX(1024);
412 texType->setDimY(256);
413 texType->compute();
414
415 Allocation *cacheAlloc = new Allocation(mRSC, texType);
416 mTextTexture.set(cacheAlloc);
417 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
418
419 // Split up our cache texture into lines of certain widths
420 int nextLine = 0;
421 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
422 nextLine += mCacheLines.top()->mMaxHeight;
423 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
424 nextLine += mCacheLines.top()->mMaxHeight;
425 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
426 nextLine += mCacheLines.top()->mMaxHeight;
427 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
428 nextLine += mCacheLines.top()->mMaxHeight;
429 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
430 nextLine += mCacheLines.top()->mMaxHeight;
431 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
432}
433
434// Avoid having to reallocate memory and render quad by quad
435void FontState::initVertexArrayBuffers()
436{
437 // Now lets write index data
438 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
439 Type *indexType = new Type(mRSC);
440 uint32_t numIndicies = mMaxNumberOfQuads * 6;
441 indexType->setDimX(numIndicies);
442 indexType->setElement(indexElem);
443 indexType->compute();
444
445 Allocation *indexAlloc = new Allocation(mRSC, indexType);
446 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
447
448 // Four verts, two triangles , six indices per quad
449 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
450 int i6 = i * 6;
451 int i4 = i * 4;
452
453 indexPtr[i6 + 0] = i4 + 0;
454 indexPtr[i6 + 1] = i4 + 1;
455 indexPtr[i6 + 2] = i4 + 2;
456
457 indexPtr[i6 + 3] = i4 + 0;
458 indexPtr[i6 + 4] = i4 + 2;
459 indexPtr[i6 + 5] = i4 + 3;
460 }
461
462 indexAlloc->deferedUploadToBufferObject(mRSC);
463 mIndexBuffer.set(indexAlloc);
464
465 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
466 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
467
468 const Element *elemArray[2];
469 elemArray[0] = posElem;
470 elemArray[1] = texElem;
471
472 String8 posName("position");
473 String8 texName("texture0");
474
475 const char *nameArray[2];
476 nameArray[0] = posName.string();
477 nameArray[1] = texName.string();
478 size_t lengths[2];
479 lengths[0] = posName.size();
480 lengths[1] = texName.size();
481
482 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths);
483
484 Type *vertexDataType = new Type(mRSC);
485 vertexDataType->setDimX(mMaxNumberOfQuads * 4);
486 vertexDataType->setElement(vertexDataElem);
487 vertexDataType->compute();
488
489 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
490 mTextMeshPtr = (float*)vertexAlloc->getPtr();
491
492 mVertexArray.set(vertexAlloc);
493}
494
495// We don't want to allocate anything unless we actually draw text
496void FontState::checkInit()
497{
498 if(mInitialized) {
499 return;
500 }
501
502 initTextTexture();
503 initRenderState();
504
505 initVertexArrayBuffers();
506
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700507 mInitialized = true;
508}
509
510void FontState::issueDrawCommand() {
511
512 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
513 mRSC->setVertex(mRSC->getDefaultProgramVertex());
514
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700515 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
516 mRSC->setRaster(mRSC->getDefaultProgramRaster());
517
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700518 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
519 mRSC->setFragment(mFontShaderF.get());
520
521 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
522 mRSC->setFragmentStore(mFontProgramStore.get());
523
524 if (!mRSC->setupCheck()) {
525 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700526 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700527 mRSC->setFragment((ProgramFragment *)tmpF.get());
528 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
529 return;
530 }
531
532 float *vtx = (float*)mVertexArray->getPtr();
533 float *tex = vtx + 3;
534
535 VertexArray va;
536 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
537 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
538 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
539
540 mIndexBuffer->uploadCheck(mRSC);
541 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
542 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
543
544 // Reset the state
545 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchoukd18c7442010-07-12 15:50:32 -0700546 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700547 mRSC->setFragment((ProgramFragment *)tmpF.get());
548 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
549}
550
551void FontState::appendMeshQuad(float x1, float y1, float z1,
552 float u1, float v1,
553 float x2, float y2, float z2,
554 float u2, float v2,
555 float x3, float y3, float z3,
556 float u3, float v3,
557 float x4, float y4, float z4,
558 float u4, float v4)
559{
560 const uint32_t vertsPerQuad = 4;
561 const uint32_t floatsPerVert = 5;
562 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
563
564 // Cull things that are off the screen
565 float width = (float)mRSC->getWidth();
566 float height = (float)mRSC->getHeight();
567
568 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
569 return;
570 }
571
572 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
573 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
574 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
575 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
576
577 (*currentPos++) = x1;
578 (*currentPos++) = y1;
579 (*currentPos++) = z1;
580 (*currentPos++) = u1;
581 (*currentPos++) = v1;
582
583 (*currentPos++) = x2;
584 (*currentPos++) = y2;
585 (*currentPos++) = z2;
586 (*currentPos++) = u2;
587 (*currentPos++) = v2;
588
589 (*currentPos++) = x3;
590 (*currentPos++) = y3;
591 (*currentPos++) = z3;
592 (*currentPos++) = u3;
593 (*currentPos++) = v3;
594
595 (*currentPos++) = x4;
596 (*currentPos++) = y4;
597 (*currentPos++) = z4;
598 (*currentPos++) = u4;
599 (*currentPos++) = v4;
600
601 mCurrentQuadIndex ++;
602
603 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
604 issueDrawCommand();
605 mCurrentQuadIndex = 0;
606 }
607}
608
609void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
610{
611 checkInit();
612
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700613 //String8 text8(text);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700614
615 // Render code here
616 Font *currentFont = mRSC->getFont();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700617 if(!currentFont) {
618 if(!mDefault.get()) {
619 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
620 }
621 currentFont = mDefault.get();
622 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700623 if(!currentFont) {
624 LOGE("Unable to initialize any fonts");
625 return;
626 }
627
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700628 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
629
630 if(mCurrentQuadIndex != 0) {
631 issueDrawCommand();
632 mCurrentQuadIndex = 0;
633 }
634}
635
636void FontState::renderText(const char *text, int x, int y)
637{
638 size_t textLen = strlen(text);
639 renderText(text, textLen, 0, -1, x, y);
640}
641
642void FontState::renderText(Allocation *alloc, int x, int y)
643{
644 if(!alloc) {
645 return;
646 }
647
648 const char *text = (const char *)alloc->getPtr();
649 size_t allocSize = alloc->getType()->getSizeBytes();
650 renderText(text, allocSize, 0, -1, x, y);
651}
652
653void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
654{
655 if(!alloc) {
656 return;
657 }
658
659 const char *text = (const char *)alloc->getPtr();
660 size_t allocSize = alloc->getType()->getSizeBytes();
661 renderText(text, allocSize, start, len, x, y);
662}
663
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700664void FontState::setFontColor(float r, float g, float b, float a) {
665 mFontColor[0] = r;
666 mFontColor[1] = g;
667 mFontColor[2] = b;
668 mFontColor[3] = a;
669 mFontColorDirty = true;
670}
671
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700672void FontState::deinit(Context *rsc)
673{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700674 mInitialized = false;
675
676 mIndexBuffer.clear();
677 mVertexArray.clear();
678
679 mFontShaderF.clear();
680 mFontSampler.clear();
681 mFontProgramStore.clear();
682
683 mTextTexture.clear();
684 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
685 delete mCacheLines[i];
686 }
687 mCacheLines.clear();
688
689 mDefault.clear();
690
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700691 Vector<Font*> fontsToDereference = mActiveFonts;
692 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
693 fontsToDereference[i]->zeroUserRef();
694 }
695
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700696 if(mLibrary) {
697 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700698 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700699 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700700}
701
702namespace android {
703namespace renderscript {
704
705RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
706{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700707 Font *newFont = Font::create(rsc, name, fontSize, dpi);
708 if(newFont) {
709 newFont->incUserRef();
710 }
711 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700712}
713
714} // renderscript
715} // android