blob: 2a47ca4f9184dd2c20c5d70bdfb61bbeaa080bc3 [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 Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700273FT_Library FontState::getLib()
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700274{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700275 if(!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700276 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700277 if(error) {
278 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700279 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700280 }
281 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700282
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700283 return mLibrary;
284}
285
286void FontState::init(Context *rsc)
287{
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700288 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-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
514 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
515 mRSC->setFragment(mFontShaderF.get());
516
517 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
518 mRSC->setFragmentStore(mFontProgramStore.get());
519
520 if (!mRSC->setupCheck()) {
521 mRSC->setVertex((ProgramVertex *)tmpV.get());
522 mRSC->setFragment((ProgramFragment *)tmpF.get());
523 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
524 return;
525 }
526
527 float *vtx = (float*)mVertexArray->getPtr();
528 float *tex = vtx + 3;
529
530 VertexArray va;
531 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
532 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
533 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
534
535 mIndexBuffer->uploadCheck(mRSC);
536 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
537 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
538
539 // Reset the state
540 mRSC->setVertex((ProgramVertex *)tmpV.get());
541 mRSC->setFragment((ProgramFragment *)tmpF.get());
542 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
543}
544
545void FontState::appendMeshQuad(float x1, float y1, float z1,
546 float u1, float v1,
547 float x2, float y2, float z2,
548 float u2, float v2,
549 float x3, float y3, float z3,
550 float u3, float v3,
551 float x4, float y4, float z4,
552 float u4, float v4)
553{
554 const uint32_t vertsPerQuad = 4;
555 const uint32_t floatsPerVert = 5;
556 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
557
558 // Cull things that are off the screen
559 float width = (float)mRSC->getWidth();
560 float height = (float)mRSC->getHeight();
561
562 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
563 return;
564 }
565
566 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
567 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
568 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
569 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
570
571 (*currentPos++) = x1;
572 (*currentPos++) = y1;
573 (*currentPos++) = z1;
574 (*currentPos++) = u1;
575 (*currentPos++) = v1;
576
577 (*currentPos++) = x2;
578 (*currentPos++) = y2;
579 (*currentPos++) = z2;
580 (*currentPos++) = u2;
581 (*currentPos++) = v2;
582
583 (*currentPos++) = x3;
584 (*currentPos++) = y3;
585 (*currentPos++) = z3;
586 (*currentPos++) = u3;
587 (*currentPos++) = v3;
588
589 (*currentPos++) = x4;
590 (*currentPos++) = y4;
591 (*currentPos++) = z4;
592 (*currentPos++) = u4;
593 (*currentPos++) = v4;
594
595 mCurrentQuadIndex ++;
596
597 if(mCurrentQuadIndex == mMaxNumberOfQuads) {
598 issueDrawCommand();
599 mCurrentQuadIndex = 0;
600 }
601}
602
603void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
604{
605 checkInit();
606
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700607 //String8 text8(text);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700608
609 // Render code here
610 Font *currentFont = mRSC->getFont();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700611 if(!currentFont) {
612 if(!mDefault.get()) {
613 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
614 }
615 currentFont = mDefault.get();
616 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700617 if(!currentFont) {
618 LOGE("Unable to initialize any fonts");
619 return;
620 }
621
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700622 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
623
624 if(mCurrentQuadIndex != 0) {
625 issueDrawCommand();
626 mCurrentQuadIndex = 0;
627 }
628}
629
630void FontState::renderText(const char *text, int x, int y)
631{
632 size_t textLen = strlen(text);
633 renderText(text, textLen, 0, -1, x, y);
634}
635
636void FontState::renderText(Allocation *alloc, int x, int y)
637{
638 if(!alloc) {
639 return;
640 }
641
642 const char *text = (const char *)alloc->getPtr();
643 size_t allocSize = alloc->getType()->getSizeBytes();
644 renderText(text, allocSize, 0, -1, x, y);
645}
646
647void FontState::renderText(Allocation *alloc, uint32_t start, int len, 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, start, len, x, y);
656}
657
658void FontState::deinit(Context *rsc)
659{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700660 mInitialized = false;
661
662 mIndexBuffer.clear();
663 mVertexArray.clear();
664
665 mFontShaderF.clear();
666 mFontSampler.clear();
667 mFontProgramStore.clear();
668
669 mTextTexture.clear();
670 for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
671 delete mCacheLines[i];
672 }
673 mCacheLines.clear();
674
675 mDefault.clear();
676
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700677 Vector<Font*> fontsToDereference = mActiveFonts;
678 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
679 fontsToDereference[i]->zeroUserRef();
680 }
681
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700682 if(mLibrary) {
683 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700684 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700685 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700686}
687
688namespace android {
689namespace renderscript {
690
691RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
692{
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700693 Font *newFont = Font::create(rsc, name, fontSize, dpi);
694 if(newFont) {
695 newFont->incUserRef();
696 }
697 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700698}
699
700} // renderscript
701} // android