blob: 833bee0ba1e708da829a06d41aaf6a404cfadaf3 [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
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 Sakhartchouk071508d2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700163 }
164
Alex Sakhartchouk071508d2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700177 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700178
179 if(!glyph->mIsValid) {
180 return;
181 }
182
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700183 uint32_t endX = startX + bitmap->width;
184 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700185
186 glyph->mBitmapMinX = startX;
187 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700188 glyph->mBitmapWidth = bitmap->width;
189 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700207
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-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 Sakhartchoukb6b34892010-06-30 16:53:43 -0700261 mLibrary = NULL;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700262 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700274FT_Library FontState::getLib()
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700275{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700276 if(!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700277 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700278 if(error) {
279 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700280 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700281 }
282 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700283
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700284 return mLibrary;
285}
286
287void FontState::init(Context *rsc)
288{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700289 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-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{
Jason Sams442a6472010-08-04 17:50:20 -0700382 uint32_t tmp[] = {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700383 RS_TEX_ENV_MODE_REPLACE, 1,
384 RS_TEX_ENV_MODE_NONE, 0,
Jason Sams442a6472010-08-04 17:50:20 -0700385 0, 0
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700386 };
Jason Sams442a6472010-08-04 17:50:20 -0700387 ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 6);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700388 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 Sakhartchouk9b949fc2010-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 Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700515 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
516 mRSC->setRaster(mRSC->getDefaultProgramRaster());
517
Alex Sakhartchouk9b949fc2010-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
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700524 if(mFontColorDirty) {
525 mFontShaderF->setConstantColor(mFontColor[0], mFontColor[1], mFontColor[2], mFontColor[3]);
526 mFontColorDirty = false;
527 }
528
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700529 if (!mRSC->setupCheck()) {
530 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700531 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700532 mRSC->setFragment((ProgramFragment *)tmpF.get());
533 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
534 return;
535 }
536
537 float *vtx = (float*)mVertexArray->getPtr();
538 float *tex = vtx + 3;
539
540 VertexArray va;
541 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
542 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
543 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
544
545 mIndexBuffer->uploadCheck(mRSC);
546 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
547 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
548
549 // Reset the state
550 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700551 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700552 mRSC->setFragment((ProgramFragment *)tmpF.get());
553 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
554}
555
556void FontState::appendMeshQuad(float x1, float y1, float z1,
557 float u1, float v1,
558 float x2, float y2, float z2,
559 float u2, float v2,
560 float x3, float y3, float z3,
561 float u3, float v3,
562 float x4, float y4, float z4,
563 float u4, float v4)
564{
565 const uint32_t vertsPerQuad = 4;
566 const uint32_t floatsPerVert = 5;
567 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
568
569 // Cull things that are off the screen
570 float width = (float)mRSC->getWidth();
571 float height = (float)mRSC->getHeight();
572
573 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
574 return;
575 }
576
577 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
578 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
579 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
580 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
581
582 (*currentPos++) = x1;
583 (*currentPos++) = y1;
584 (*currentPos++) = z1;
585 (*currentPos++) = u1;
586 (*currentPos++) = v1;
587
588 (*currentPos++) = x2;
589 (*currentPos++) = y2;
590 (*currentPos++) = z2;
591 (*currentPos++) = u2;
592 (*currentPos++) = v2;
593
594 (*currentPos++) = x3;
595 (*currentPos++) = y3;
596 (*currentPos++) = z3;
597 (*currentPos++) = u3;
598 (*currentPos++) = v3;
599
600 (*currentPos++) = x4;
601 (*currentPos++) = y4;
602 (*currentPos++) = z4;
603 (*currentPos++) = u4;
604 (*currentPos++) = v4;
605
606 mCurrentQuadIndex ++;
607
608 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
609 issueDrawCommand();
610 mCurrentQuadIndex = 0;
611 }
612}
613
614void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
615{
616 checkInit();
617
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700618 //String8 text8(text);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700619
620 // Render code here
621 Font *currentFont = mRSC->getFont();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700622 if(!currentFont) {
623 if(!mDefault.get()) {
624 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
625 }
626 currentFont = mDefault.get();
627 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700628 if(!currentFont) {
629 LOGE("Unable to initialize any fonts");
630 return;
631 }
632
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700633 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
634
635 if(mCurrentQuadIndex != 0) {
636 issueDrawCommand();
637 mCurrentQuadIndex = 0;
638 }
639}
640
641void FontState::renderText(const char *text, int x, int y)
642{
643 size_t textLen = strlen(text);
644 renderText(text, textLen, 0, -1, x, y);
645}
646
647void FontState::renderText(Allocation *alloc, int x, int y)
648{
649 if(!alloc) {
650 return;
651 }
652
653 const char *text = (const char *)alloc->getPtr();
654 size_t allocSize = alloc->getType()->getSizeBytes();
655 renderText(text, allocSize, 0, -1, x, y);
656}
657
658void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
659{
660 if(!alloc) {
661 return;
662 }
663
664 const char *text = (const char *)alloc->getPtr();
665 size_t allocSize = alloc->getType()->getSizeBytes();
666 renderText(text, allocSize, start, len, x, y);
667}
668
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700669void FontState::setFontColor(float r, float g, float b, float a) {
670 mFontColor[0] = r;
671 mFontColor[1] = g;
672 mFontColor[2] = b;
673 mFontColor[3] = a;
674 mFontColorDirty = true;
675}
676
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700677void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
678 *r = mFontColor[0];
679 *g = mFontColor[1];
680 *b = mFontColor[2];
681 *a = mFontColor[3];
682}
683
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700684void FontState::deinit(Context *rsc)
685{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700686 mInitialized = false;
687
688 mIndexBuffer.clear();
689 mVertexArray.clear();
690
691 mFontShaderF.clear();
692 mFontSampler.clear();
693 mFontProgramStore.clear();
694
695 mTextTexture.clear();
696 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
697 delete mCacheLines[i];
698 }
699 mCacheLines.clear();
700
701 mDefault.clear();
702
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700703 Vector<Font*> fontsToDereference = mActiveFonts;
704 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
705 fontsToDereference[i]->zeroUserRef();
706 }
707
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700708 if(mLibrary) {
709 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700710 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700711 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700712}
713
714namespace android {
715namespace renderscript {
716
717RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
718{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700719 Font *newFont = Font::create(rsc, name, fontSize, dpi);
720 if(newFont) {
721 newFont->incUserRef();
722 }
723 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700724}
725
726} // renderscript
727} // android