fix performance problems with using multiple font sizes

This commit is contained in:
dborth 2009-07-08 07:14:18 +00:00
parent ae13bd130e
commit d5e43d1048
6 changed files with 85 additions and 111 deletions

View File

@ -22,25 +22,35 @@
#include "FreeTypeGX.h" #include "FreeTypeGX.h"
/** static FT_Library ftLibrary; /**< FreeType FT_Library instance. */
* Default constructor for the FreeTypeGX class. static FT_Face ftFace; /**< FreeType reusable FT_Face typographic object. */
* static FT_GlyphSlot ftSlot; /**< FreeType reusable FT_GlyphSlot glyph container object. */
* @param textureFormat Optional format (GX_TF_*) of the texture as defined by the libogc gx.h header file. If not specified default value is GX_TF_RGBA8.
* @param vertexIndex Optional vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file. If not specified default value is GX_VTXFMT1.
*/
FreeTypeGX::FreeTypeGX(uint8_t textureFormat, uint8_t vertexIndex) {
FT_Init_FreeType(&this->ftLibrary);
this->textureFormat = textureFormat; FreeTypeGX *fontSystem[50];
this->setVertexFormat(vertexIndex);
this->setCompatibilityMode(FTGX_COMPATIBILITY_NONE); void InitFreeType(uint8_t* fontBuffer, FT_Long bufferSize)
{
FT_Init_FreeType(&ftLibrary);
FT_New_Memory_Face(ftLibrary, (FT_Byte *)fontBuffer, bufferSize, 0, &ftFace);
ftSlot = ftFace->glyph;
for(int i=0; i<50; i++)
fontSystem[i] = NULL;
} }
/** void ChangeFontSize(FT_UInt pixelSize)
* Default destructor for the FreeTypeGX class. {
*/ FT_Set_Pixel_Sizes(ftFace, 0, pixelSize);
FreeTypeGX::~FreeTypeGX() { }
this->unloadFont();
void ClearFontData()
{
for(int i=0; i<50; i++)
{
if(fontSystem[i])
delete fontSystem[i];
fontSystem[i] = NULL;
}
} }
/** /**
@ -52,23 +62,38 @@ FreeTypeGX::~FreeTypeGX() {
* @param strChar Character string to be converted. * @param strChar Character string to be converted.
* @return Wide character representation of supplied character string. * @return Wide character representation of supplied character string.
*/ */
wchar_t* FreeTypeGX::charToWideChar(char* strChar) {
wchar_t *strWChar;
strWChar = new wchar_t[strlen(strChar) + 1];
char *tempSrc = strChar; wchar_t* charToWideChar(const char* strChar)
wchar_t *tempDest = strWChar; {
while((*tempDest++ = *tempSrc++)); wchar_t *strWChar;
strWChar = new wchar_t[strlen(strChar) + 1];
return strWChar; char *tempSrc = (char *)strChar;
wchar_t *tempDest = strWChar;
while((*tempDest++ = *tempSrc++));
return strWChar;
} }
/** /**
* Default constructor for the FreeTypeGX class.
* *
* \overload * @param textureFormat Optional format (GX_TF_*) of the texture as defined by the libogc gx.h header file. If not specified default value is GX_TF_RGBA8.
* @param vertexIndex Optional vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file. If not specified default value is GX_VTXFMT1.
*/ */
wchar_t* FreeTypeGX::charToWideChar(const char* strChar) { FreeTypeGX::FreeTypeGX(FT_UInt pixelSize, uint8_t textureFormat, uint8_t vertexIndex) {
return FreeTypeGX::charToWideChar((char*) strChar); this->textureFormat = textureFormat;
this->setVertexFormat(vertexIndex);
this->setCompatibilityMode(FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_PASSCLR | FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE);
this->ftPointSize = pixelSize;
this->ftKerningEnabled = FT_HAS_KERNING(ftFace);
}
/**
* Default destructor for the FreeTypeGX class.
*/
FreeTypeGX::~FreeTypeGX() {
this->unloadFont();
} }
/** /**
@ -149,43 +174,6 @@ void FreeTypeGX::setDefaultMode() {
} }
} }
/**
* Loads and processes a specified true type font buffer to a specific point size.
*
* This routine takes a precompiled true type font buffer and loads the necessary processed data into memory. This routine should be called before drawText will succeed.
*
* @param fontBuffer A pointer in memory to a precompiled true type font buffer.
* @param bufferSize Size of the true type font buffer in bytes.
* @param pointSize The desired point size this wrapper's configured font face.
* @param cacheAll Optional flag to specify if all font characters should be cached when the class object is created. If specified as false the characters only become cached the first time they are used. If not specified default value is false.
*/
uint16_t FreeTypeGX::loadFont(uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll) {
this->unloadFont();
this->ftPointSize = pointSize;
FT_New_Memory_Face(this->ftLibrary, (FT_Byte *)fontBuffer, bufferSize, 0, &this->ftFace);
if(this->ftPointSize > 0)
FT_Set_Pixel_Sizes(this->ftFace, 0, this->ftPointSize);
this->ftSlot = this->ftFace->glyph;
this->ftKerningEnabled = FT_HAS_KERNING(this->ftFace);
if (cacheAll) {
return this->cacheGlyphDataComplete();
}
return 0;
}
/**
*
* \overload
*/
uint16_t FreeTypeGX::loadFont(const uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll) {
return this->loadFont((uint8_t *)fontBuffer, bufferSize, pointSize, cacheAll);
}
/** /**
* Clears all loaded font glyph data. * Clears all loaded font glyph data.
* *
@ -195,9 +183,6 @@ void FreeTypeGX::unloadFont() {
if(this->fontData.size() == 0) if(this->fontData.size() == 0)
return; return;
GX_DrawDone();
GX_Flush();
for( std::map<wchar_t, ftgxCharData>::iterator i = this->fontData.begin(); i != this->fontData.end(); i++) { for( std::map<wchar_t, ftgxCharData>::iterator i = this->fontData.begin(); i != this->fontData.end(); i++) {
free(i->second.glyphDataTexture); free(i->second.glyphDataTexture);
} }
@ -205,12 +190,6 @@ void FreeTypeGX::unloadFont() {
this->fontData.clear(); this->fontData.clear();
} }
void FreeTypeGX::changeSize(FT_UInt pointSize) {
this->unloadFont();
this->ftPointSize = pointSize;
FT_Set_Pixel_Sizes(this->ftFace, 0, this->ftPointSize);
}
/** /**
* Adjusts the texture data buffer to necessary width for a given texture format. * Adjusts the texture data buffer to necessary width for a given texture format.
* *
@ -286,24 +265,24 @@ ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode) {
FT_UInt gIndex; FT_UInt gIndex;
uint16_t textureWidth = 0, textureHeight = 0; uint16_t textureWidth = 0, textureHeight = 0;
gIndex = FT_Get_Char_Index( this->ftFace, charCode ); gIndex = FT_Get_Char_Index( ftFace, charCode );
if (!FT_Load_Glyph(this->ftFace, gIndex, FT_LOAD_DEFAULT )) { if (!FT_Load_Glyph(ftFace, gIndex, FT_LOAD_DEFAULT )) {
FT_Render_Glyph( this->ftSlot, FT_RENDER_MODE_NORMAL ); FT_Render_Glyph( ftSlot, FT_RENDER_MODE_NORMAL );
if(this->ftSlot->format == FT_GLYPH_FORMAT_BITMAP) { if(ftSlot->format == FT_GLYPH_FORMAT_BITMAP) {
FT_Bitmap *glyphBitmap = &this->ftSlot->bitmap; FT_Bitmap *glyphBitmap = &ftSlot->bitmap;
textureWidth = adjustTextureWidth(glyphBitmap->width, this->textureFormat); textureWidth = adjustTextureWidth(glyphBitmap->width, this->textureFormat);
textureHeight = adjustTextureHeight(glyphBitmap->rows, this->textureFormat); textureHeight = adjustTextureHeight(glyphBitmap->rows, this->textureFormat);
this->fontData[charCode] = (ftgxCharData){ this->fontData[charCode] = (ftgxCharData){
this->ftSlot->advance.x >> 6, ftSlot->advance.x >> 6,
gIndex, gIndex,
textureWidth, textureWidth,
textureHeight, textureHeight,
this->ftSlot->bitmap_top, ftSlot->bitmap_top,
this->ftSlot->bitmap_top, ftSlot->bitmap_top,
textureHeight - this->ftSlot->bitmap_top, textureHeight - ftSlot->bitmap_top,
NULL NULL
}; };
this->loadGlyphData(glyphBitmap, &this->fontData[charCode]); this->loadGlyphData(glyphBitmap, &this->fontData[charCode]);
@ -324,14 +303,14 @@ ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode) {
uint16_t FreeTypeGX::cacheGlyphDataComplete() { uint16_t FreeTypeGX::cacheGlyphDataComplete() {
uint16_t i = 0; uint16_t i = 0;
FT_UInt gIndex; FT_UInt gIndex;
FT_ULong charCode = FT_Get_First_Char( this->ftFace, &gIndex ); FT_ULong charCode = FT_Get_First_Char( ftFace, &gIndex );
while ( gIndex != 0 ) { while ( gIndex != 0 ) {
if(this->cacheGlyphData(charCode) != NULL) { if(this->cacheGlyphData(charCode) != NULL) {
i++; i++;
} }
charCode = FT_Get_Next_Char( this->ftFace, charCode, &gIndex ); charCode = FT_Get_Next_Char( ftFace, charCode, &gIndex );
} }
return i; return i;
@ -471,7 +450,7 @@ uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, wchar_t *text, GXColor color
if(glyphData != NULL) { if(glyphData != NULL) {
if(this->ftKerningEnabled && i) { if(this->ftKerningEnabled && i) {
FT_Get_Kerning( this->ftFace, this->fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta ); FT_Get_Kerning( ftFace, this->fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta );
x_pos += pairDelta.x >> 6; x_pos += pairDelta.x >> 6;
} }
@ -561,7 +540,7 @@ uint16_t FreeTypeGX::getWidth(wchar_t *text) {
if(glyphData != NULL) { if(glyphData != NULL) {
if(this->ftKerningEnabled && (i > 0)) { if(this->ftKerningEnabled && (i > 0)) {
FT_Get_Kerning( this->ftFace, this->fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta ); FT_Get_Kerning( ftFace, this->fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta );
strWidth += pairDelta.x >> 6; strWidth += pairDelta.x >> 6;
} }

View File

@ -220,6 +220,11 @@ typedef struct ftgxDataOffset_ {
const GXColor ftgxWhite = (GXColor){0xff, 0xff, 0xff, 0xff}; /**< Constant color value used only to sanitize Doxygen documentation. */ const GXColor ftgxWhite = (GXColor){0xff, 0xff, 0xff, 0xff}; /**< Constant color value used only to sanitize Doxygen documentation. */
void InitFreeType(uint8_t* fontBuffer, FT_Long bufferSize);
void ChangeFontSize(FT_UInt pixelSize);
wchar_t* charToWideChar(const char* p);
void ClearFontData();
/*! \class FreeTypeGX /*! \class FreeTypeGX
* \brief Wrapper class for the libFreeType library with GX rendering. * \brief Wrapper class for the libFreeType library with GX rendering.
* \author Armin Tamzarian * \author Armin Tamzarian
@ -232,9 +237,6 @@ const GXColor ftgxWhite = (GXColor){0xff, 0xff, 0xff, 0xff}; /**< Constant color
class FreeTypeGX { class FreeTypeGX {
private: private:
FT_Library ftLibrary; /**< FreeType FT_Library instance. */
FT_Face ftFace; /**< FreeType reusable FT_Face typographic object. */
FT_GlyphSlot ftSlot; /**< FreeType reusable FT_GlyphSlot glyph container object. */
FT_UInt ftPointSize; /**< Requested size of the rendered font. */ FT_UInt ftPointSize; /**< Requested size of the rendered font. */
bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */ bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */
@ -261,18 +263,12 @@ class FreeTypeGX {
void copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, GXColor color); void copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, GXColor color);
public: public:
FreeTypeGX(uint8_t textureFormat = GX_TF_RGBA8, uint8_t vertexIndex = GX_VTXFMT1); FreeTypeGX(FT_UInt pixelSize, uint8_t textureFormat = GX_TF_RGBA8, uint8_t vertexIndex = GX_VTXFMT1);
~FreeTypeGX(); ~FreeTypeGX();
static wchar_t* charToWideChar(char* p);
static wchar_t* charToWideChar(const char* p);
void setVertexFormat(uint8_t vertexIndex); void setVertexFormat(uint8_t vertexIndex);
void setCompatibilityMode(uint32_t compatibilityMode); void setCompatibilityMode(uint32_t compatibilityMode);
uint16_t loadFont(uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll = false);
uint16_t loadFont(const uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll = false);
void changeSize(FT_UInt pointSize);
uint16_t drawText(int16_t x, int16_t y, wchar_t *text, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL); uint16_t drawText(int16_t x, int16_t y, wchar_t *text, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL);
uint16_t drawText(int16_t x, int16_t y, wchar_t const *text, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL); uint16_t drawText(int16_t x, int16_t y, wchar_t const *text, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL);

View File

@ -50,7 +50,7 @@
#include "input.h" #include "input.h"
#include "oggplayer.h" #include "oggplayer.h"
extern FreeTypeGX *fontSystem; extern FreeTypeGX *fontSystem[];
#define SCROLL_INITIAL_DELAY 20 #define SCROLL_INITIAL_DELAY 20
#define SCROLL_LOOP_DELAY 3 #define SCROLL_LOOP_DELAY 3

View File

@ -46,7 +46,7 @@ GuiText::GuiText(const char * t, int s, GXColor c)
if(t) if(t)
{ {
origText = strdup(t); origText = strdup(t);
text = fontSystem->charToWideChar((char *)t); text = charToWideChar(t);
} }
} }
@ -75,7 +75,7 @@ GuiText::GuiText(const char * t)
if(t) if(t)
{ {
origText = strdup(t); origText = strdup(t);
text = fontSystem->charToWideChar((char *)t); text = charToWideChar(t);
} }
} }
@ -110,7 +110,7 @@ void GuiText::SetText(const char * t)
if(t) if(t)
{ {
origText = strdup(t); origText = strdup(t);
text = fontSystem->charToWideChar((char *)t); text = charToWideChar(t);
} }
} }
@ -218,7 +218,9 @@ void GuiText::Draw()
if(newSize != currentSize) if(newSize != currentSize)
{ {
fontSystem->changeSize(newSize); ChangeFontSize(newSize);
if(!fontSystem[newSize])
fontSystem[newSize] = new FreeTypeGX(newSize);
currentSize = newSize; currentSize = newSize;
} }
@ -236,7 +238,7 @@ void GuiText::Draw()
{ {
if(strlen(tmpText) > maxChar) if(strlen(tmpText) > maxChar)
tmpText[maxChar] = 0; tmpText[maxChar] = 0;
textDyn = fontSystem->charToWideChar(tmpText); textDyn = charToWideChar(tmpText);
} }
if(textScroll == SCROLL_HORIZONTAL) if(textScroll == SCROLL_HORIZONTAL)
@ -270,11 +272,11 @@ void GuiText::Draw()
strncat(&tmpText[dynlen+2], origText, maxChar - dynlen - 2); strncat(&tmpText[dynlen+2], origText, maxChar - dynlen - 2);
} }
if(textDyn) delete textDyn; if(textDyn) delete textDyn;
textDyn = fontSystem->charToWideChar(tmpText); textDyn = charToWideChar(tmpText);
} }
} }
if(textDyn) if(textDyn)
fontSystem->drawText(this->GetLeft(), this->GetTop()+voffset, textDyn, c, style); fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop()+voffset, textDyn, c, style);
} }
else if(wrap) else if(wrap)
{ {
@ -328,19 +330,19 @@ void GuiText::Draw()
for(i=0; i < linenum; i++) for(i=0; i < linenum; i++)
{ {
fontSystem->drawText(this->GetLeft(), this->GetTop()+voffset+i*lineheight, textrow[i], c, style); fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop()+voffset+i*lineheight, textrow[i], c, style);
delete textrow[i]; delete textrow[i];
} }
} }
else else
{ {
fontSystem->drawText(this->GetLeft(), this->GetTop()+voffset, textDyn, c, style); fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop()+voffset, textDyn, c, style);
} }
free(tmpText); free(tmpText);
} }
else else
{ {
fontSystem->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style); fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style);
} }
this->UpdateEffects(); this->UpdateEffects();
} }

View File

@ -64,7 +64,6 @@ int ResetRequested = 0;
int ExitRequested = 0; int ExitRequested = 0;
char appPath[1024]; char appPath[1024];
int appLoadMethod = METHOD_AUTO; int appLoadMethod = METHOD_AUTO;
FreeTypeGX *fontSystem;
/**************************************************************************** /****************************************************************************
* Shutdown / Reboot / Exit * Shutdown / Reboot / Exit
@ -438,9 +437,7 @@ main(int argc, char *argv[])
S9xInitSync(); // initialize frame sync S9xInitSync(); // initialize frame sync
// Initialize font system // Initialize font system
fontSystem = new FreeTypeGX(); InitFreeType((u8*)font_ttf, font_ttf_size);
fontSystem->loadFont(font_ttf, font_ttf_size, 0);
fontSystem->setCompatibilityMode(FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_PASSCLR | FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE);
InitGUIThreads(); InitGUIThreads();

View File

@ -100,6 +100,6 @@ extern int ShutdownRequested;
extern int ExitRequested; extern int ExitRequested;
extern char appPath[]; extern char appPath[];
extern int appLoadMethod; extern int appLoadMethod;
extern FreeTypeGX *fontSystem; extern FreeTypeGX *fontSystem[];
#endif #endif