00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "FreeTypeGX.h"
00024
00025 static FT_Library ftLibrary;
00026 static FT_Face ftFace;
00027 static FT_GlyphSlot ftSlot;
00028
00029 FreeTypeGX *fontSystem[MAX_FONT_SIZE+1];
00030
00031 void InitFreeType(uint8_t* fontBuffer, FT_Long bufferSize)
00032 {
00033 FT_Init_FreeType(&ftLibrary);
00034 FT_New_Memory_Face(ftLibrary, (FT_Byte *)fontBuffer, bufferSize, 0, &ftFace);
00035 ftSlot = ftFace->glyph;
00036
00037 for(int i=0; i<50; i++)
00038 fontSystem[i] = NULL;
00039 }
00040
00041 void ChangeFontSize(FT_UInt pixelSize)
00042 {
00043 FT_Set_Pixel_Sizes(ftFace, 0, pixelSize);
00044 }
00045
00046 void ClearFontData()
00047 {
00048 for(int i=0; i<50; i++)
00049 {
00050 if(fontSystem[i])
00051 delete fontSystem[i];
00052 fontSystem[i] = NULL;
00053 }
00054 }
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 wchar_t* charToWideChar(const char* strChar)
00067 {
00068 wchar_t *strWChar;
00069 strWChar = new wchar_t[strlen(strChar) + 1];
00070
00071 char *tempSrc = (char *)strChar;
00072 wchar_t *tempDest = strWChar;
00073 while((*tempDest++ = *tempSrc++));
00074
00075 return strWChar;
00076 }
00077
00078
00079
00080
00081
00082
00083
00084 FreeTypeGX::FreeTypeGX(FT_UInt pixelSize, uint8_t textureFormat, uint8_t vertexIndex)
00085 {
00086 this->textureFormat = textureFormat;
00087 this->setVertexFormat(vertexIndex);
00088 this->setCompatibilityMode(FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_PASSCLR | FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE);
00089 this->ftPointSize = pixelSize;
00090 this->ftKerningEnabled = FT_HAS_KERNING(ftFace);
00091 this->z = 0;
00092 }
00093
00094
00095
00096
00097 FreeTypeGX::~FreeTypeGX()
00098 {
00099 this->unloadFont();
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 void FreeTypeGX::setVertexFormat(uint8_t vertexIndex)
00112 {
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 this->vertexIndex = vertexIndex;
00123 GX_SetVtxAttrFmt(this->vertexIndex, GX_VA_POS, GX_POS_XY, GX_S16, 0);
00124
00125 GX_SetVtxAttrFmt(this->vertexIndex, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
00126 GX_SetVtxAttrFmt(this->vertexIndex, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
00127 }
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 void FreeTypeGX::setCompatibilityMode(uint32_t compatibilityMode)
00140 {
00141 this->compatibilityMode = compatibilityMode;
00142 }
00143
00144
00145
00146
00147
00148
00149
00150 void FreeTypeGX::setDefaultMode()
00151 {
00152 if(this->compatibilityMode)
00153 {
00154 switch(this->compatibilityMode & 0x00FF)
00155 {
00156 case FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_MODULATE:
00157 GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
00158 break;
00159 case FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_DECAL:
00160 GX_SetTevOp(GX_TEVSTAGE0, GX_DECAL);
00161 break;
00162 case FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_BLEND:
00163 GX_SetTevOp(GX_TEVSTAGE0, GX_BLEND);
00164 break;
00165 case FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_REPLACE:
00166 GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE);
00167 break;
00168 case FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_PASSCLR:
00169 GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
00170 break;
00171 default:
00172 break;
00173 }
00174
00175 switch(this->compatibilityMode & 0xFF00)
00176 {
00177 case FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE:
00178 GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
00179 break;
00180 case FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_DIRECT:
00181 GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
00182 break;
00183 case FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_INDEX8:
00184 GX_SetVtxDesc(GX_VA_TEX0, GX_INDEX8);
00185 break;
00186 case FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_INDEX16:
00187 GX_SetVtxDesc(GX_VA_TEX0, GX_INDEX16);
00188 break;
00189 default:
00190 break;
00191 }
00192 }
00193 }
00194
00195
00196
00197
00198
00199
00200 void FreeTypeGX::unloadFont()
00201 {
00202 if(this->fontData.size() == 0)
00203 return;
00204 for(std::map<wchar_t, ftgxCharData>::iterator i = this->fontData.begin(); i != this->fontData.end(); i++)
00205 free(i->second.glyphDataTexture);
00206 this->fontData.clear();
00207 }
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 uint16_t FreeTypeGX::adjustTextureWidth(uint16_t textureWidth, uint8_t textureFormat)
00219 {
00220 uint16_t alignment;
00221
00222 switch(textureFormat)
00223 {
00224 case GX_TF_I4:
00225 case GX_TF_I8:
00226 case GX_TF_IA4:
00227 alignment = 8;
00228 break;
00229
00230 case GX_TF_IA8:
00231 case GX_TF_RGB565:
00232 case GX_TF_RGB5A3:
00233 case GX_TF_RGBA8:
00234 default:
00235 alignment = 4;
00236 break;
00237 }
00238 return textureWidth % alignment == 0 ? textureWidth : alignment + textureWidth - (textureWidth % alignment);
00239 }
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 uint16_t FreeTypeGX::adjustTextureHeight(uint16_t textureHeight, uint8_t textureFormat)
00251 {
00252 uint16_t alignment;
00253
00254 switch(textureFormat)
00255 {
00256 case GX_TF_I4:
00257 alignment = 8;
00258 break;
00259
00260 case GX_TF_I8:
00261 case GX_TF_IA4:
00262 case GX_TF_IA8:
00263 case GX_TF_RGB565:
00264 case GX_TF_RGB5A3:
00265 case GX_TF_RGBA8:
00266 default:
00267 alignment = 4;
00268 break;
00269 }
00270 return textureHeight % alignment == 0 ? textureHeight : alignment + textureHeight - (textureHeight % alignment);
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode)
00283 {
00284 FT_UInt gIndex;
00285 uint16_t textureWidth = 0, textureHeight = 0;
00286
00287 gIndex = FT_Get_Char_Index( ftFace, charCode );
00288 if (!FT_Load_Glyph(ftFace, gIndex, FT_LOAD_DEFAULT )) {
00289 FT_Render_Glyph( ftSlot, FT_RENDER_MODE_NORMAL );
00290
00291 if(ftSlot->format == FT_GLYPH_FORMAT_BITMAP) {
00292 FT_Bitmap *glyphBitmap = &ftSlot->bitmap;
00293
00294 textureWidth = adjustTextureWidth(glyphBitmap->width, this->textureFormat);
00295 textureHeight = adjustTextureHeight(glyphBitmap->rows, this->textureFormat);
00296
00297 this->fontData[charCode] = (ftgxCharData){
00298 ftSlot->bitmap_left,
00299 ftSlot->advance.x >> 6,
00300 gIndex,
00301 textureWidth,
00302 textureHeight,
00303 ftSlot->bitmap_top,
00304 ftSlot->bitmap_top,
00305 glyphBitmap->rows - ftSlot->bitmap_top,
00306 NULL
00307 };
00308 this->loadGlyphData(glyphBitmap, &this->fontData[charCode]);
00309
00310 return &this->fontData[charCode];
00311 }
00312 }
00313 return NULL;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322 uint16_t FreeTypeGX::cacheGlyphDataComplete()
00323 {
00324 uint16_t i = 0;
00325 FT_UInt gIndex;
00326 FT_ULong charCode = FT_Get_First_Char( ftFace, &gIndex );
00327 while ( gIndex != 0 )
00328 {
00329 if(this->cacheGlyphData(charCode) != NULL)
00330 i++;
00331 charCode = FT_Get_Next_Char( ftFace, charCode, &gIndex );
00332 }
00333 return i;
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData)
00346 {
00347 uint32_t *glyphData = (uint32_t *)memalign(32, charData->textureWidth * charData->textureHeight * 4);
00348 memset(glyphData, 0x00, charData->textureWidth * charData->textureHeight * 4);
00349
00350 for (uint16_t imagePosY = 0; imagePosY < bmp->rows; imagePosY++)
00351 {
00352 for (uint16_t imagePosX = 0; imagePosX < bmp->width; imagePosX++)
00353 {
00354 uint32_t pixel = (uint32_t) bmp->buffer[imagePosY * bmp->width + imagePosX];
00355 glyphData[imagePosY * charData->textureWidth + imagePosX] = 0x00000000 | (pixel << 24) | (pixel << 16) | (pixel << 8) | pixel;
00356 }
00357 }
00358
00359 switch(this->textureFormat)
00360 {
00361 case GX_TF_I4:
00362 charData->glyphDataTexture = Metaphrasis::convertBufferToI4(glyphData, charData->textureWidth, charData->textureHeight);
00363 break;
00364 case GX_TF_I8:
00365 charData->glyphDataTexture = Metaphrasis::convertBufferToI8(glyphData, charData->textureWidth, charData->textureHeight);
00366 break;
00367 case GX_TF_IA4:
00368 charData->glyphDataTexture = Metaphrasis::convertBufferToIA4(glyphData, charData->textureWidth, charData->textureHeight);
00369 break;
00370 case GX_TF_IA8:
00371 charData->glyphDataTexture = Metaphrasis::convertBufferToIA8(glyphData, charData->textureWidth, charData->textureHeight);
00372 break;
00373 case GX_TF_RGB565:
00374 charData->glyphDataTexture = Metaphrasis::convertBufferToRGB565(glyphData, charData->textureWidth, charData->textureHeight);
00375 break;
00376 case GX_TF_RGB5A3:
00377 charData->glyphDataTexture = Metaphrasis::convertBufferToRGB5A3(glyphData, charData->textureWidth, charData->textureHeight);
00378 break;
00379 case GX_TF_RGBA8:
00380 default:
00381 charData->glyphDataTexture = Metaphrasis::convertBufferToRGBA8(glyphData, charData->textureWidth, charData->textureHeight);
00382 break;
00383 }
00384 free(glyphData);
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 int16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format)
00396 {
00397 if (format & FTGX_JUSTIFY_LEFT)
00398 return 0;
00399 else if (format & FTGX_JUSTIFY_CENTER)
00400 return -(width >> 1);
00401 else if (format & FTGX_JUSTIFY_RIGHT)
00402 return -width;
00403 return 0;
00404 }
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 int16_t FreeTypeGX::getStyleOffsetHeight(ftgxDataOffset *offset, uint16_t format)
00415 {
00416 switch(format & FTGX_ALIGN_MASK)
00417 {
00418 case FTGX_ALIGN_TOP:
00419 return offset->ascender;
00420
00421 default:
00422 case FTGX_ALIGN_MIDDLE:
00423 return (offset->ascender + offset->descender + 1) >> 1;
00424
00425 case FTGX_ALIGN_BOTTOM:
00426 return offset->descender;
00427
00428 case FTGX_ALIGN_BASELINE:
00429 return 0;
00430
00431 case FTGX_ALIGN_GLYPH_TOP:
00432 return offset->max;
00433
00434 case FTGX_ALIGN_GLYPH_MIDDLE:
00435 return (offset->max + offset->min + 1) >> 1;
00436
00437 case FTGX_ALIGN_GLYPH_BOTTOM:
00438 return offset->min;
00439 }
00440 return 0;
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456 uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, wchar_t *text, GXColor color, uint16_t textStyle)
00457 {
00458 uint16_t strLength = wcslen(text);
00459 uint16_t x_pos = x, printed = 0;
00460 uint16_t x_offset = 0, y_offset = 0;
00461 GXTexObj glyphTexture;
00462 FT_Vector pairDelta;
00463 ftgxDataOffset offset;
00464
00465 if(textStyle & FTGX_JUSTIFY_MASK)
00466 {
00467 x_offset = this->getStyleOffsetWidth(this->getWidth(text), textStyle);
00468 }
00469 if(textStyle & FTGX_ALIGN_MASK)
00470 {
00471 this->getOffset(text, &offset);
00472 y_offset = this->getStyleOffsetHeight(&offset, textStyle);
00473 }
00474
00475 for (uint16_t i = 0; i < strLength; i++)
00476 {
00477 ftgxCharData* glyphData = NULL;
00478 if( this->fontData.find(text[i]) != this->fontData.end() )
00479 {
00480 glyphData = &this->fontData[text[i]];
00481 }
00482 else
00483 {
00484 glyphData = this->cacheGlyphData(text[i]);
00485 }
00486
00487 if(glyphData != NULL)
00488 {
00489 if(this->ftKerningEnabled && i)
00490 {
00491 FT_Get_Kerning( ftFace, this->fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta );
00492 x_pos += pairDelta.x >> 6;
00493 }
00494
00495 GX_InitTexObj(&glyphTexture, glyphData->glyphDataTexture, glyphData->textureWidth, glyphData->textureHeight, this->textureFormat, GX_CLAMP, GX_CLAMP, GX_FALSE);
00496 this->copyTextureToFramebuffer(&glyphTexture, glyphData->textureWidth, glyphData->textureHeight, x_pos + glyphData->renderOffsetX + x_offset, y - glyphData->renderOffsetY + y_offset, color);
00497
00498 x_pos += glyphData->glyphAdvanceX;
00499 printed++;
00500 }
00501 }
00502
00503 if(textStyle & FTGX_STYLE_MASK)
00504 {
00505 this->getOffset(text, &offset);
00506 this->drawTextFeature(x + x_offset, y + y_offset, this->getWidth(text), &offset, textStyle, color);
00507 }
00508
00509 return printed;
00510 }
00511
00512
00513
00514
00515 uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, wchar_t const *text, GXColor color, uint16_t textStyle)
00516 {
00517 return this->drawText(x, y, (wchar_t *)text, color, textStyle);
00518 }
00519
00520 void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color)
00521 {
00522 uint16_t featureHeight = this->ftPointSize >> 4 > 0 ? this->ftPointSize >> 4 : 1;
00523
00524 if (format & FTGX_STYLE_UNDERLINE)
00525 this->copyFeatureToFramebuffer(width, featureHeight, x, y + 1, color);
00526
00527 if (format & FTGX_STYLE_STRIKE)
00528 this->copyFeatureToFramebuffer(width, featureHeight, x, y - ((offsetData->max) >> 1), color);
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540 uint16_t FreeTypeGX::getWidth(wchar_t *text)
00541 {
00542 uint16_t strLength = wcslen(text);
00543 uint16_t strWidth = 0;
00544 FT_Vector pairDelta;
00545
00546 for (uint16_t i = 0; i < strLength; i++)
00547 {
00548
00549 ftgxCharData* glyphData = NULL;
00550 if( this->fontData.find(text[i]) != this->fontData.end() )
00551 {
00552 glyphData = &this->fontData[text[i]];
00553 }
00554 else
00555 {
00556 glyphData = this->cacheGlyphData(text[i]);
00557 }
00558
00559 if(glyphData != NULL)
00560 {
00561 if(this->ftKerningEnabled && (i > 0))
00562 {
00563 FT_Get_Kerning( ftFace, this->fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta );
00564 strWidth += pairDelta.x >> 6;
00565 }
00566 strWidth += glyphData->glyphAdvanceX;
00567 }
00568 }
00569 return strWidth;
00570 }
00571
00572
00573
00574
00575
00576 uint16_t FreeTypeGX::getWidth(wchar_t const *text)
00577 {
00578 return this->getWidth((wchar_t *)text);
00579 }
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590 uint16_t FreeTypeGX::getHeight(wchar_t *text)
00591 {
00592 ftgxDataOffset offset;
00593 this->getOffset(text, &offset);
00594 return offset.max - offset.min;
00595 }
00596
00597
00598
00599
00600
00601 uint16_t FreeTypeGX::getHeight(wchar_t const *text)
00602 {
00603 return this->getHeight((wchar_t *)text);
00604 }
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616 void FreeTypeGX::getOffset(wchar_t *text, ftgxDataOffset* offset)
00617 {
00618 uint16_t strLength = wcslen(text);
00619 int16_t strMax = 0, strMin = 9999;
00620
00621 for (uint16_t i = 0; i < strLength; i++)
00622 {
00623
00624 ftgxCharData* glyphData = NULL;
00625 if( this->fontData.find(text[i]) != this->fontData.end() )
00626 {
00627 glyphData = &this->fontData[text[i]];
00628 }
00629 else
00630 {
00631 glyphData = this->cacheGlyphData(text[i]);
00632 }
00633
00634 if(glyphData != NULL)
00635 {
00636 strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax;
00637 strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin;
00638 }
00639 }
00640 offset->ascender = ftFace->size->metrics.ascender>>6;
00641 offset->descender = ftFace->size->metrics.descender>>6;
00642 offset->max = strMax;
00643 offset->min = strMin;
00644 }
00645
00646
00647
00648
00649
00650 void FreeTypeGX::getOffset(wchar_t const *text, ftgxDataOffset* offset)
00651 {
00652 this->getOffset(text, offset);
00653 }
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, GXColor color)
00668 {
00669 GX_LoadTexObj(texObj, GX_TEXMAP0);
00670 GX_InvalidateTexAll();
00671
00672 GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE);
00673 GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT);
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683 GX_Begin(GX_QUADS, this->vertexIndex, 4);
00684 GX_Position2s16(screenX, screenY);
00685 GX_Color4u8(color.r, color.g, color.b, color.a);
00686 GX_TexCoord2f32(0.0f, 0.0f);
00687
00688 GX_Position2s16(texWidth + screenX, screenY);
00689 GX_Color4u8(color.r, color.g, color.b, color.a);
00690 GX_TexCoord2f32(1.0f, 0.0f);
00691
00692 GX_Position2s16(texWidth + screenX, texHeight + screenY);
00693 GX_Color4u8(color.r, color.g, color.b, color.a);
00694 GX_TexCoord2f32(1.0f, 1.0f);
00695
00696 GX_Position2s16(screenX, texHeight + screenY);
00697 GX_Color4u8(color.r, color.g, color.b, color.a);
00698 GX_TexCoord2f32(0.0f, 1.0f);
00699 GX_End();
00700
00701 this->setDefaultMode();
00702 }
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 void FreeTypeGX::copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, GXColor color)
00716 {
00717 GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
00718 GX_SetVtxDesc (GX_VA_TEX0, GX_NONE);
00719
00720
00721
00722
00723
00724
00725
00726
00727 GX_Begin(GX_QUADS, this->vertexIndex, 4);
00728 GX_Position2s16(screenX, screenY);
00729 GX_Color4u8(color.r, color.g, color.b, color.a);
00730
00731 GX_Position2s16(featureWidth + screenX, screenY);
00732 GX_Color4u8(color.r, color.g, color.b, color.a);
00733
00734 GX_Position2s16(featureWidth + screenX, featureHeight + screenY);
00735 GX_Color4u8(color.r, color.g, color.b, color.a);
00736
00737 GX_Position2s16(screenX, featureHeight + screenY);
00738 GX_Color4u8(color.r, color.g, color.b, color.a);
00739 GX_End();
00740
00741 this->setDefaultMode();
00742 }