blob: 694ea1654b0da19cd6b5410d0d273eabbbd6e5eb [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;
42}
43
44bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi)
45{
46 if(mInitialized) {
47 LOGE("Reinitialization of fonts not supported");
48 return false;
49 }
50
51 String8 fontsDir("/fonts/");
52 String8 fullPath(getenv("ANDROID_ROOT"));
53 fullPath += fontsDir;
54 fullPath += name;
55
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -070056 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070057 if(error) {
58 LOGE("Unable to initialize font %s", fullPath.string());
59 return false;
60 }
61
62 mFontName = name;
63 mFontSize = fontSize;
64 mDpi = dpi;
65
66 //LOGE("Font initialized: %s", fullPath.string());
67
68 error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
69 if(error) {
70 LOGE("Unable to set font size on %s", fullPath.string());
71 return false;
72 }
73
74 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070075
76 mInitialized = true;
77 return true;
78}
79
80void Font::invalidateTextureCache()
81{
82 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
83 mCachedGlyphs.valueAt(i)->mIsValid = false;
84 }
85}
86
87void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y)
88{
89 FontState *state = &mRSC->mStateFont;
90
91 int nPenX = x + glyph->mBitmapLeft;
92 int nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
93
94 state->appendMeshQuad(nPenX, nPenY, 0,
95 glyph->mBitmapMinU, glyph->mBitmapMaxV,
96
97 nPenX + (int)glyph->mBitmapWidth, nPenY, 0,
98 glyph->mBitmapMaxU, glyph->mBitmapMaxV,
99
100 nPenX + (int)glyph->mBitmapWidth, nPenY - (int)glyph->mBitmapHeight, 0,
101 glyph->mBitmapMaxU, glyph->mBitmapMinV,
102
103 nPenX, nPenY - (int)glyph->mBitmapHeight, 0,
104 glyph->mBitmapMinU, glyph->mBitmapMinV);
105}
106
107void Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y)
108{
109 if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
110 return;
111 }
112
113 int penX = x, penY = y;
114 int glyphsLeft = 1;
115 if(numGlyphs > 0) {
116 glyphsLeft = numGlyphs;
117 }
118
119 size_t index = start;
120 size_t nextIndex = 0;
121
122 while (glyphsLeft > 0) {
123
124 int32_t utfChar = utf32_at(text, len, index, &nextIndex);
125
126 // Reached the end of the string or encountered
127 if(utfChar < 0) {
128 break;
129 }
130
131 // Move to the next character in the array
132 index = nextIndex;
133
134 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
135
136 if(cachedGlyph == NULL) {
137 cachedGlyph = cacheGlyph((uint32_t)utfChar);
138 }
139 // Is the glyph still in texture cache?
140 if(!cachedGlyph->mIsValid) {
141 updateGlyphCache(cachedGlyph);
142 }
143
144 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
145 if(cachedGlyph->mIsValid) {
146 drawCachedGlyph(cachedGlyph, penX, penY);
147 }
148
149 penX += (cachedGlyph->mAdvance.x >> 6);
150
151 // If we were given a specific number of glyphs, decrement
152 if(numGlyphs > 0) {
153 glyphsLeft --;
154 }
155 }
156}
157
158void Font::updateGlyphCache(CachedGlyphInfo *glyph)
159{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700160 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
161 if(error) {
162 LOGE("Couldn't load glyph.");
163 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700164 }
165
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700166 glyph->mAdvance = mFace->glyph->advance;
167 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
168 glyph->mBitmapTop = mFace->glyph->bitmap_top;
169
170 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
171
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700172 // Now copy the bitmap into the cache texture
173 uint32_t startX = 0;
174 uint32_t startY = 0;
175
176 // Let the font state figure out where to put the bitmap
177 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700178 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700179
180 if(!glyph->mIsValid) {
181 return;
182 }
183
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700184 uint32_t endX = startX + bitmap->width;
185 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700186
187 glyph->mBitmapMinX = startX;
188 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700189 glyph->mBitmapWidth = bitmap->width;
190 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700191
192 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
193 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
194
195 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
196 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
197 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
198 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
199}
200
201Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
202{
203 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
204 mCachedGlyphs.add(glyph, newGlyph);
205
206 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
207 newGlyph->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700208
209 //LOGE("Glyph = %c, face index: %u", (unsigned char)glyph, newGlyph->mGlyphIndex);
210
211 updateGlyphCache(newGlyph);
212
213 return newGlyph;
214}
215
216Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
217{
218 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
219
220 for(uint32_t i = 0; i < activeFonts.size(); i ++) {
221 Font *ithFont = activeFonts[i];
222 if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700223 return ithFont;
224 }
225 }
226
227 Font *newFont = new Font(rsc);
228 bool isInitialized = newFont->init(name, fontSize, dpi);
229 if(isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700230 activeFonts.push(newFont);
231 return newFont;
232 }
233
234 delete newFont;
235 return NULL;
236
237}
238
239Font::~Font()
240{
241 if(mFace) {
242 FT_Done_Face(mFace);
243 }
244
245 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
246 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
247 mRSC->mStateFont.mActiveFonts.removeAt(ct);
248 break;
249 }
250 }
251
252 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
253 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700254 delete glyph;
255 }
256}
257
258FontState::FontState()
259{
260 mInitialized = false;
261 mMaxNumberOfQuads = 1024;
262 mCurrentQuadIndex = 0;
263 mRSC = NULL;
264}
265
266FontState::~FontState()
267{
268 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
269 delete mCacheLines[i];
270 }
271
272 rsAssert(!mActiveFonts.size());
273}
274
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700275FT_Library FontState::getLib()
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700276{
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700277 if(!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700278 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700279 if(error) {
280 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700281 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700282 }
283 }
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700284 return mLibrary;
285}
286
287void FontState::init(Context *rsc)
288{
289 //getLib();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700290
291 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700292}
293
294void FontState::flushAllAndInvalidate()
295{
296 if(mCurrentQuadIndex != 0) {
297 issueDrawCommand();
298 mCurrentQuadIndex = 0;
299 }
300 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
301 mActiveFonts[i]->invalidateTextureCache();
302 }
303 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
304 mCacheLines[i]->mCurrentCol = 0;
305 }
306}
307
308bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
309{
310 // If the glyph is too tall, don't cache it
311 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
312 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
313 return false;
314 }
315
316 // Now copy the bitmap into the cache texture
317 uint32_t startX = 0;
318 uint32_t startY = 0;
319
320 bool bitmapFit = false;
321 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
322 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
323 if(bitmapFit) {
324 break;
325 }
326 }
327
328 // If the new glyph didn't fit, flush the state so far and invalidate everything
329 if(!bitmapFit) {
330 flushAllAndInvalidate();
331
332 // Try to fit it again
333 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
334 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
335 if(bitmapFit) {
336 break;
337 }
338 }
339
340 // if we still don't fit, something is wrong and we shouldn't draw
341 if(!bitmapFit) {
342 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
343 return false;
344 }
345 }
346
347 *retOriginX = startX;
348 *retOriginY = startY;
349
350 uint32_t endX = startX + bitmap->width;
351 uint32_t endY = startY + bitmap->rows;
352
353 //LOGE("Bitmap width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
354
355 uint32_t cacheWidth = getCacheTextureType()->getDimX();
356
357 unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
358 unsigned char *bitmapBuffer = bitmap->buffer;
359
360 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
361 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
362 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
363 unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
364 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
365 }
366 }
367
368 // This will dirty the texture and the shader so next time
369 // we draw it will upload the data
370 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
371 mFontShaderF->bindTexture(0, mTextTexture.get());
372
373 // Some debug code
374 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
375 LOGE("Cache Line: H: %u Empty Space: %f",
376 mCacheLines[i]->mMaxHeight,
377 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
378
379 }*/
380
381 return true;
382}
383
384void FontState::initRenderState()
385{
386 uint32_t tmp[5] = {
387 RS_TEX_ENV_MODE_REPLACE, 1,
388 RS_TEX_ENV_MODE_NONE, 0,
389 0
390 };
391 ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 5);
392 mFontShaderF.set(pf);
393 mFontShaderF->init(mRSC);
394
395 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
396 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
397 mFontSampler.set(sampler);
398 mFontShaderF->bindSampler(0, sampler);
399
400 ProgramStore *fontStore = new ProgramStore(mRSC);
401 mFontProgramStore.set(fontStore);
402 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
403 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
404 mFontProgramStore->setDitherEnable(false);
405 mFontProgramStore->setDepthMask(false);
406}
407
408void FontState::initTextTexture()
409{
410 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
411
412 // We will allocate a texture to initially hold 32 character bitmaps
413 Type *texType = new Type(mRSC);
414 texType->setElement(alphaElem);
415 texType->setDimX(1024);
416 texType->setDimY(256);
417 texType->compute();
418
419 Allocation *cacheAlloc = new Allocation(mRSC, texType);
420 mTextTexture.set(cacheAlloc);
421 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
422
423 // Split up our cache texture into lines of certain widths
424 int nextLine = 0;
425 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
426 nextLine += mCacheLines.top()->mMaxHeight;
427 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
428 nextLine += mCacheLines.top()->mMaxHeight;
429 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
430 nextLine += mCacheLines.top()->mMaxHeight;
431 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
432 nextLine += mCacheLines.top()->mMaxHeight;
433 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
434 nextLine += mCacheLines.top()->mMaxHeight;
435 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
436}
437
438// Avoid having to reallocate memory and render quad by quad
439void FontState::initVertexArrayBuffers()
440{
441 // Now lets write index data
442 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
443 Type *indexType = new Type(mRSC);
444 uint32_t numIndicies = mMaxNumberOfQuads * 6;
445 indexType->setDimX(numIndicies);
446 indexType->setElement(indexElem);
447 indexType->compute();
448
449 Allocation *indexAlloc = new Allocation(mRSC, indexType);
450 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
451
452 // Four verts, two triangles , six indices per quad
453 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
454 int i6 = i * 6;
455 int i4 = i * 4;
456
457 indexPtr[i6 + 0] = i4 + 0;
458 indexPtr[i6 + 1] = i4 + 1;
459 indexPtr[i6 + 2] = i4 + 2;
460
461 indexPtr[i6 + 3] = i4 + 0;
462 indexPtr[i6 + 4] = i4 + 2;
463 indexPtr[i6 + 5] = i4 + 3;
464 }
465
466 indexAlloc->deferedUploadToBufferObject(mRSC);
467 mIndexBuffer.set(indexAlloc);
468
469 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
470 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
471
472 const Element *elemArray[2];
473 elemArray[0] = posElem;
474 elemArray[1] = texElem;
475
476 String8 posName("position");
477 String8 texName("texture0");
478
479 const char *nameArray[2];
480 nameArray[0] = posName.string();
481 nameArray[1] = texName.string();
482 size_t lengths[2];
483 lengths[0] = posName.size();
484 lengths[1] = texName.size();
485
486 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths);
487
488 Type *vertexDataType = new Type(mRSC);
489 vertexDataType->setDimX(mMaxNumberOfQuads * 4);
490 vertexDataType->setElement(vertexDataElem);
491 vertexDataType->compute();
492
493 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
494 mTextMeshPtr = (float*)vertexAlloc->getPtr();
495
496 mVertexArray.set(vertexAlloc);
497}
498
499// We don't want to allocate anything unless we actually draw text
500void FontState::checkInit()
501{
502 if(mInitialized) {
503 return;
504 }
505
506 initTextTexture();
507 initRenderState();
508
509 initVertexArrayBuffers();
510
511 /*mTextMeshRefs = new ObjectBaseRef<SimpleMesh>[mNumMeshes];
512
513 for(uint32_t i = 0; i < mNumMeshes; i ++){
514 SimpleMesh *textMesh = createTextMesh();
515 mTextMeshRefs[i].set(textMesh);
516 }*/
517
518 mInitialized = true;
519}
520
521void FontState::issueDrawCommand() {
522
523 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
524 mRSC->setVertex(mRSC->getDefaultProgramVertex());
525
526 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
527 mRSC->setFragment(mFontShaderF.get());
528
529 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
530 mRSC->setFragmentStore(mFontProgramStore.get());
531
532 if (!mRSC->setupCheck()) {
533 mRSC->setVertex((ProgramVertex *)tmpV.get());
534 mRSC->setFragment((ProgramFragment *)tmpF.get());
535 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
536 return;
537 }
538
539 float *vtx = (float*)mVertexArray->getPtr();
540 float *tex = vtx + 3;
541
542 VertexArray va;
543 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
544 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
545 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
546
547 mIndexBuffer->uploadCheck(mRSC);
548 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
549 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
550
551 // Reset the state
552 mRSC->setVertex((ProgramVertex *)tmpV.get());
553 mRSC->setFragment((ProgramFragment *)tmpF.get());
554 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
555}
556
557void FontState::appendMeshQuad(float x1, float y1, float z1,
558 float u1, float v1,
559 float x2, float y2, float z2,
560 float u2, float v2,
561 float x3, float y3, float z3,
562 float u3, float v3,
563 float x4, float y4, float z4,
564 float u4, float v4)
565{
566 const uint32_t vertsPerQuad = 4;
567 const uint32_t floatsPerVert = 5;
568 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
569
570 // Cull things that are off the screen
571 float width = (float)mRSC->getWidth();
572 float height = (float)mRSC->getHeight();
573
574 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
575 return;
576 }
577
578 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
579 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
580 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
581 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
582
583 (*currentPos++) = x1;
584 (*currentPos++) = y1;
585 (*currentPos++) = z1;
586 (*currentPos++) = u1;
587 (*currentPos++) = v1;
588
589 (*currentPos++) = x2;
590 (*currentPos++) = y2;
591 (*currentPos++) = z2;
592 (*currentPos++) = u2;
593 (*currentPos++) = v2;
594
595 (*currentPos++) = x3;
596 (*currentPos++) = y3;
597 (*currentPos++) = z3;
598 (*currentPos++) = u3;
599 (*currentPos++) = v3;
600
601 (*currentPos++) = x4;
602 (*currentPos++) = y4;
603 (*currentPos++) = z4;
604 (*currentPos++) = u4;
605 (*currentPos++) = v4;
606
607 mCurrentQuadIndex ++;
608
609 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
610 issueDrawCommand();
611 mCurrentQuadIndex = 0;
612 }
613}
614
615void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
616{
617 checkInit();
618
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700619 //String8 text8(text);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700620
621 // Render code here
622 Font *currentFont = mRSC->getFont();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700623 if(!currentFont) {
624 if(!mDefault.get()) {
625 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
626 }
627 currentFont = mDefault.get();
628 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700629 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
630
631 if(mCurrentQuadIndex != 0) {
632 issueDrawCommand();
633 mCurrentQuadIndex = 0;
634 }
635}
636
637void FontState::renderText(const char *text, int x, int y)
638{
639 size_t textLen = strlen(text);
640 renderText(text, textLen, 0, -1, x, y);
641}
642
643void FontState::renderText(Allocation *alloc, int x, int y)
644{
645 if(!alloc) {
646 return;
647 }
648
649 const char *text = (const char *)alloc->getPtr();
650 size_t allocSize = alloc->getType()->getSizeBytes();
651 renderText(text, allocSize, 0, -1, x, y);
652}
653
654void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
655{
656 if(!alloc) {
657 return;
658 }
659
660 const char *text = (const char *)alloc->getPtr();
661 size_t allocSize = alloc->getType()->getSizeBytes();
662 renderText(text, allocSize, start, len, x, y);
663}
664
665void FontState::deinit(Context *rsc)
666{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700667 mInitialized = false;
668
669 mIndexBuffer.clear();
670 mVertexArray.clear();
671
672 mFontShaderF.clear();
673 mFontSampler.clear();
674 mFontProgramStore.clear();
675
676 mTextTexture.clear();
677 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
678 delete mCacheLines[i];
679 }
680 mCacheLines.clear();
681
682 mDefault.clear();
683
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700684 if(mLibrary) {
685 FT_Done_FreeType( mLibrary );
686 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700687}
688
689namespace android {
690namespace renderscript {
691
692RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
693{
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700694 Font *newFont = Font::create(rsc, name, fontSize, dpi);
695 if(newFont) {
696 newFont->incUserRef();
697 }
698 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700699}
700
701} // renderscript
702} // android