usbloadergx/source/FreeTypeGX.cpp

610 lines
19 KiB
C++
Raw Normal View History

/*
* FreeTypeGX is a wrapper class for libFreeType which renders a compiled
* FreeType parsable font into a GX texture for Wii homebrew development.
* Copyright (C) 2008 Armin Tamzarian
* Modified by Dimok, 2010
*
* This file is part of FreeTypeGX.
*
* FreeTypeGX is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeTypeGX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FreeTypeGX. If not, see <http://www.gnu.org/licenses/>.
*/
#include "FreeTypeGX.h"
OK since the Wii System Menu Player is released now as I already mentioned the source for the loader will also be put on SVN again. Now that i am done with merging here is the MOD17 source. Changelog since last revision: - add banner/icon animation support for wii games / channels / gamecube - add custom banner for gamecube which loads the gamecube internal opening.bnr information (it is much better than the generic one of the system menu) (big thanks to diddy from the wiithemeteam for creating the brlyt/brlan for the banner) - add gamecube banner of system menu (not used right now since it sucks) - add banner grid of the system menu (resources loaded from nand) (with button highliter) - add big banner frame window of the system menu (resources loaded from nand). the banner window has buttons "Settings" and "Start" by default. if parental control is enabled the "Settings" button is replaced by "Back" - add play count text to the banner frame window (can be disabled as up until now in the gui settings) - add zoom in/out/scroll animations to banner grid and change into big frame window - add loading gc banners from ISO and DVD - add loading wii banners from DVD discs even if the game is not installed - add favorite level setting to the game settings since it is no longer on the banner frame window - add new settings section for banner settings - add option to choose between disc window and banner window - added back ehci module to support 2 usb drives and re-enabled the option - add option for 2 usb drives for d2x cIOS as well (will be supported in the future, not yet) - exchanged "GC Games" and "EmuNand Channels" on the game selection screen (more space for translators) - add and fixed gui numpad for entering numbers of any kind - add setting for tooltip delay time - fix reload of cover image on game list when only 1 item is left after a change (e.g. sort) - add use of old build in font for credits window because it doesnt look good with the system menu one - fixed effect bug when scrolling buttons in the settings and the wiimote is over button 1 - fixed bug where entering -1 (Use global) for cIOS was not possible in game settings - many source cleanups - add bnr chace setting - add DML configuration from the loader - removed creation of temporary "boot.bin" file - DML custom game paths. Additionally i added support for following forms of paths: 1. configpath/gamepath/game.iso 2. configpath/gamepath/game.gcm 3. configpath/gamepath/GAMEID6.iso 4. configpath/gamepath/GAMEID6.gcm Where gamepath can be anything you want inside the configure path in the custom path settings. I don't know if GCM files are allowed by DML but i just added support for it just in case. Changing path to USB is not blocked currently but games won't run from USB just keep that in mind. The "copy to SD before start" feature is not added yet. Listing the games should work though - DML cheats now work the same way as for wii, gct goes to "Cheatcode Path" as GAMEID.gct (same as on wii) - several DML internal configs are added as per game/global settings - added load of last cheat configuration from GCT files - added init of network into background thread so it is cancelable and has a timeout - added gc games copy from USB to SD on demand with choice menu to delete SD games to make space, SD games path can be chosen seperately from main gc path. all dupicate sd games are prefered then the main path to allow direct boot of games that are already on sd. main path can be on USB or anywhere else. - added gc disc dump functionality with multidisc, compress and align support (thanks to FIX94 and Overjoy for their disc dump source on which this is based) - added selection menu for gc multidisc which game to install - fixed loading game ID when it can't be read from path for GC games and with that loading the titles from GameTDB for them - lots of string handling improvements (thanks to gerbilsoft for his patch) - added gamecube banner cache loading (only loading) if available with GAMEID6.bnr or ID3.bnr in the banner cache path. wii games/channels also accept now ID3.bnr. - added several progress bar cancel buttons on some missing progress windows - improved calculation of progress speed. now it is always the last 15 secs average instead of overall progress speed. - added pulsing new icon on banner grid layout for new games - added resize of widescreen screenshots to 768 width - added mii extract on save game extract if the file does not yet exists - added mii extractor and SYSCONF extractor that always extracts and overwrites old files - changed wifi gecko to UDP socket - support for DML v1.2+ NOTE: Banner animation support requires AHBPROT flag to be enabled. If you use old HBC you should use our forwarder or update the HBC otherwise you wont have that support. I am hoping that now the themers and the translators can catch up with their stuff for the next upcomming official release.
2012-05-06 12:59:58 +02:00
#include "memory/mem2.h"
using namespace std;
#define ALIGN8(x) (((x) + 7) & ~7)
/**
* Convert a short char string to a wide char string.
*
* This routine converts a supplied short character string into a wide character string.
* Note that it is the user's responsibility to clear the returned buffer once it is no longer needed.
*
* @param strChar Character string to be converted.
* @return Wide character representation of supplied character string.
*/
2010-09-24 02:48:03 +02:00
wchar_t* charToWideChar(const char* strChar)
{
if (!strChar) return NULL;
wchar_t *strWChar = new (std::nothrow) wchar_t[strlen(strChar) + 1];
if (!strWChar) return NULL;
int bt = mbstowcs(strWChar, strChar, strlen(strChar));
if (bt > 0)
{
strWChar[bt] = 0;
return strWChar;
}
wchar_t *tempDest = strWChar;
while ((*tempDest++ = *strChar++))
;
return strWChar;
}
/**
* Default constructor for the FreeTypeGX class for WiiXplorer.
*/
FreeTypeGX::FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize, bool lastFace)
{
int faceIndex = 0;
ftPointSize = 0;
FT_Init_FreeType(&ftLibrary);
if(lastFace)
{
FT_New_Memory_Face(ftLibrary, (FT_Byte *)fontBuffer, bufferSize, -1, &ftFace);
faceIndex = ftFace->num_faces - 1; // Use the last face
FT_Done_Face(ftFace);
ftFace = NULL;
}
FT_New_Memory_Face(ftLibrary, (FT_Byte *) fontBuffer, bufferSize, faceIndex, &ftFace);
setVertexFormat(GX_VTXFMT1);
ftKerningEnabled = false;//FT_HAS_KERNING(ftFace);
}
/**
* Default destructor for the FreeTypeGX class.
*/
FreeTypeGX::~FreeTypeGX()
{
unloadFont();
FT_Done_Face(ftFace);
FT_Done_FreeType(ftLibrary);
}
/**
* Setup the vertex attribute formats for the glyph textures.
*
* This function sets up the vertex format for the glyph texture on the specified vertex format index.
* Note that this function should not need to be called except if the vertex formats are cleared or the specified
* vertex format index is modified.
*
* @param vertexIndex Vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file.
2010-09-24 02:48:03 +02:00
*/
void FreeTypeGX::setVertexFormat(uint8_t vertexInd)
{
vertexIndex = vertexInd;
GX_SetVtxAttrFmt(vertexIndex, GX_VA_POS, GX_POS_XYZ, GX_S16, 0);
GX_SetVtxAttrFmt(vertexIndex, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GX_SetVtxAttrFmt(vertexIndex, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
}
/**
* Clears all loaded font glyph data.
*
* This routine clears all members of the font map structure and frees all allocated memory back to the system.
*/
void FreeTypeGX::unloadFont()
{
if (this->fontData.size() == 0) return;
map<int16_t, map<wchar_t, ftgxCharData> >::iterator itr;
map<wchar_t, ftgxCharData>::iterator itr2;
for (itr = fontData.begin(); itr != fontData.end(); itr++)
{
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++)
OK since the Wii System Menu Player is released now as I already mentioned the source for the loader will also be put on SVN again. Now that i am done with merging here is the MOD17 source. Changelog since last revision: - add banner/icon animation support for wii games / channels / gamecube - add custom banner for gamecube which loads the gamecube internal opening.bnr information (it is much better than the generic one of the system menu) (big thanks to diddy from the wiithemeteam for creating the brlyt/brlan for the banner) - add gamecube banner of system menu (not used right now since it sucks) - add banner grid of the system menu (resources loaded from nand) (with button highliter) - add big banner frame window of the system menu (resources loaded from nand). the banner window has buttons "Settings" and "Start" by default. if parental control is enabled the "Settings" button is replaced by "Back" - add play count text to the banner frame window (can be disabled as up until now in the gui settings) - add zoom in/out/scroll animations to banner grid and change into big frame window - add loading gc banners from ISO and DVD - add loading wii banners from DVD discs even if the game is not installed - add favorite level setting to the game settings since it is no longer on the banner frame window - add new settings section for banner settings - add option to choose between disc window and banner window - added back ehci module to support 2 usb drives and re-enabled the option - add option for 2 usb drives for d2x cIOS as well (will be supported in the future, not yet) - exchanged "GC Games" and "EmuNand Channels" on the game selection screen (more space for translators) - add and fixed gui numpad for entering numbers of any kind - add setting for tooltip delay time - fix reload of cover image on game list when only 1 item is left after a change (e.g. sort) - add use of old build in font for credits window because it doesnt look good with the system menu one - fixed effect bug when scrolling buttons in the settings and the wiimote is over button 1 - fixed bug where entering -1 (Use global) for cIOS was not possible in game settings - many source cleanups - add bnr chace setting - add DML configuration from the loader - removed creation of temporary "boot.bin" file - DML custom game paths. Additionally i added support for following forms of paths: 1. configpath/gamepath/game.iso 2. configpath/gamepath/game.gcm 3. configpath/gamepath/GAMEID6.iso 4. configpath/gamepath/GAMEID6.gcm Where gamepath can be anything you want inside the configure path in the custom path settings. I don't know if GCM files are allowed by DML but i just added support for it just in case. Changing path to USB is not blocked currently but games won't run from USB just keep that in mind. The "copy to SD before start" feature is not added yet. Listing the games should work though - DML cheats now work the same way as for wii, gct goes to "Cheatcode Path" as GAMEID.gct (same as on wii) - several DML internal configs are added as per game/global settings - added load of last cheat configuration from GCT files - added init of network into background thread so it is cancelable and has a timeout - added gc games copy from USB to SD on demand with choice menu to delete SD games to make space, SD games path can be chosen seperately from main gc path. all dupicate sd games are prefered then the main path to allow direct boot of games that are already on sd. main path can be on USB or anywhere else. - added gc disc dump functionality with multidisc, compress and align support (thanks to FIX94 and Overjoy for their disc dump source on which this is based) - added selection menu for gc multidisc which game to install - fixed loading game ID when it can't be read from path for GC games and with that loading the titles from GameTDB for them - lots of string handling improvements (thanks to gerbilsoft for his patch) - added gamecube banner cache loading (only loading) if available with GAMEID6.bnr or ID3.bnr in the banner cache path. wii games/channels also accept now ID3.bnr. - added several progress bar cancel buttons on some missing progress windows - improved calculation of progress speed. now it is always the last 15 secs average instead of overall progress speed. - added pulsing new icon on banner grid layout for new games - added resize of widescreen screenshots to 768 width - added mii extract on save game extract if the file does not yet exists - added mii extractor and SYSCONF extractor that always extracts and overwrites old files - changed wifi gecko to UDP socket - support for DML v1.2+ NOTE: Banner animation support requires AHBPROT flag to be enabled. If you use old HBC you should use our forwarder or update the HBC otherwise you wont have that support. I am hoping that now the themers and the translators can catch up with their stuff for the next upcomming official release.
2012-05-06 12:59:58 +02:00
MEM2_free(itr2->second.glyphDataTexture);
itr->second.clear();
}
fontData.clear();
ftgxAlign.clear();
}
/**
* Caches the given font glyph in the instance font texture buffer.
*
* This routine renders and stores the requested glyph's bitmap and relevant information into its own quickly addressible
* structure within an instance-specific map.
*
* @param charCode The requested glyph's character code.
* @return A pointer to the allocated font structure.
*/
2010-09-24 02:48:03 +02:00
ftgxCharData * FreeTypeGX::cacheGlyphData(wchar_t charCode, int16_t pixelSize)
{
map<int16_t, map<wchar_t, ftgxCharData> >::iterator itr = fontData.find(pixelSize);
if (itr != fontData.end())
{
map<wchar_t, ftgxCharData>::iterator itr2 = itr->second.find(charCode);
if (itr2 != itr->second.end())
{
return &itr2->second;
}
}
FT_UInt gIndex;
uint16_t textureWidth = 0, textureHeight = 0;
if (ftPointSize != pixelSize)
{
ftPointSize = pixelSize;
FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize);
//!Cache ascender and decender as well
map<int16_t, ftgxDataOffset>::iterator itrAlign = ftgxAlign.find(ftPointSize);
if (itrAlign == ftgxAlign.end())
{
ftgxAlign[ftPointSize].ascender = (int16_t) ftFace->size->metrics.ascender >> 6;
ftgxAlign[ftPointSize].descender = (int16_t) ftFace->size->metrics.descender >> 6;
ftgxAlign[ftPointSize].max = 0;
ftgxAlign[ftPointSize].min = 0;
}
}
gIndex = FT_Get_Char_Index(ftFace, (FT_ULong) charCode);
if (gIndex != 0 && FT_Load_Glyph(ftFace, gIndex, FT_LOAD_DEFAULT | FT_LOAD_RENDER) == 0)
{
if (ftFace->glyph->format == FT_GLYPH_FORMAT_BITMAP)
{
FT_Bitmap *glyphBitmap = &ftFace->glyph->bitmap;
textureWidth = ALIGN8(glyphBitmap->width);
textureHeight = ALIGN8(glyphBitmap->rows);
if(textureWidth == 0)
textureWidth = 8;
if(textureHeight == 0)
textureHeight = 8;
fontData[pixelSize][charCode].renderOffsetX = (int16_t) ftFace->glyph->bitmap_left;
fontData[pixelSize][charCode].glyphAdvanceX = (uint16_t) (ftFace->glyph->advance.x >> 6);
fontData[pixelSize][charCode].glyphIndex = (uint32_t) gIndex;
fontData[pixelSize][charCode].textureWidth = (uint16_t) textureWidth;
fontData[pixelSize][charCode].textureHeight = (uint16_t) textureHeight;
fontData[pixelSize][charCode].renderOffsetY = (int16_t) ftFace->glyph->bitmap_top;
fontData[pixelSize][charCode].renderOffsetMax = (int16_t) ftFace->glyph->bitmap_top;
fontData[pixelSize][charCode].renderOffsetMin = (int16_t) glyphBitmap->rows - ftFace->glyph->bitmap_top;
fontData[pixelSize][charCode].glyphDataTexture = NULL;
loadGlyphData(glyphBitmap, &fontData[pixelSize][charCode]);
return &fontData[pixelSize][charCode];
}
}
return NULL;
}
/**
* Locates each character in this wrapper's configured font face and proccess them.
*
* This routine locates each character in the configured font face and renders the glyph's bitmap.
* Each bitmap and relevant information is loaded into its own quickly addressible structure within an instance-specific map.
*/
2010-09-24 02:48:03 +02:00
uint16_t FreeTypeGX::cacheGlyphDataComplete(int16_t pixelSize)
{
uint32_t i = 0;
FT_UInt gIndex;
FT_ULong charCode = FT_Get_First_Char(ftFace, &gIndex);
while (gIndex != 0)
{
if (cacheGlyphData(charCode, pixelSize) != NULL) ++i;
charCode = FT_Get_Next_Char(ftFace, charCode, &gIndex);
}
return (uint16_t) (i);
}
/**
* Loads the rendered bitmap into the relevant structure's data buffer.
*
* This routine does a simple byte-wise copy of the glyph's rendered 8-bit grayscale bitmap into the structure's buffer.
* Each byte is converted from the bitmap's intensity value into the a uint32_t RGBA value.
*
* @param bmp A pointer to the most recently rendered glyph's bitmap.
* @param charData A pointer to an allocated ftgxCharData structure whose data represent that of the last rendered glyph.
*/
2010-09-24 02:48:03 +02:00
void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData)
{
int glyphSize = (charData->textureWidth * charData->textureHeight) >> 1;
OK since the Wii System Menu Player is released now as I already mentioned the source for the loader will also be put on SVN again. Now that i am done with merging here is the MOD17 source. Changelog since last revision: - add banner/icon animation support for wii games / channels / gamecube - add custom banner for gamecube which loads the gamecube internal opening.bnr information (it is much better than the generic one of the system menu) (big thanks to diddy from the wiithemeteam for creating the brlyt/brlan for the banner) - add gamecube banner of system menu (not used right now since it sucks) - add banner grid of the system menu (resources loaded from nand) (with button highliter) - add big banner frame window of the system menu (resources loaded from nand). the banner window has buttons "Settings" and "Start" by default. if parental control is enabled the "Settings" button is replaced by "Back" - add play count text to the banner frame window (can be disabled as up until now in the gui settings) - add zoom in/out/scroll animations to banner grid and change into big frame window - add loading gc banners from ISO and DVD - add loading wii banners from DVD discs even if the game is not installed - add favorite level setting to the game settings since it is no longer on the banner frame window - add new settings section for banner settings - add option to choose between disc window and banner window - added back ehci module to support 2 usb drives and re-enabled the option - add option for 2 usb drives for d2x cIOS as well (will be supported in the future, not yet) - exchanged "GC Games" and "EmuNand Channels" on the game selection screen (more space for translators) - add and fixed gui numpad for entering numbers of any kind - add setting for tooltip delay time - fix reload of cover image on game list when only 1 item is left after a change (e.g. sort) - add use of old build in font for credits window because it doesnt look good with the system menu one - fixed effect bug when scrolling buttons in the settings and the wiimote is over button 1 - fixed bug where entering -1 (Use global) for cIOS was not possible in game settings - many source cleanups - add bnr chace setting - add DML configuration from the loader - removed creation of temporary "boot.bin" file - DML custom game paths. Additionally i added support for following forms of paths: 1. configpath/gamepath/game.iso 2. configpath/gamepath/game.gcm 3. configpath/gamepath/GAMEID6.iso 4. configpath/gamepath/GAMEID6.gcm Where gamepath can be anything you want inside the configure path in the custom path settings. I don't know if GCM files are allowed by DML but i just added support for it just in case. Changing path to USB is not blocked currently but games won't run from USB just keep that in mind. The "copy to SD before start" feature is not added yet. Listing the games should work though - DML cheats now work the same way as for wii, gct goes to "Cheatcode Path" as GAMEID.gct (same as on wii) - several DML internal configs are added as per game/global settings - added load of last cheat configuration from GCT files - added init of network into background thread so it is cancelable and has a timeout - added gc games copy from USB to SD on demand with choice menu to delete SD games to make space, SD games path can be chosen seperately from main gc path. all dupicate sd games are prefered then the main path to allow direct boot of games that are already on sd. main path can be on USB or anywhere else. - added gc disc dump functionality with multidisc, compress and align support (thanks to FIX94 and Overjoy for their disc dump source on which this is based) - added selection menu for gc multidisc which game to install - fixed loading game ID when it can't be read from path for GC games and with that loading the titles from GameTDB for them - lots of string handling improvements (thanks to gerbilsoft for his patch) - added gamecube banner cache loading (only loading) if available with GAMEID6.bnr or ID3.bnr in the banner cache path. wii games/channels also accept now ID3.bnr. - added several progress bar cancel buttons on some missing progress windows - improved calculation of progress speed. now it is always the last 15 secs average instead of overall progress speed. - added pulsing new icon on banner grid layout for new games - added resize of widescreen screenshots to 768 width - added mii extract on save game extract if the file does not yet exists - added mii extractor and SYSCONF extractor that always extracts and overwrites old files - changed wifi gecko to UDP socket - support for DML v1.2+ NOTE: Banner animation support requires AHBPROT flag to be enabled. If you use old HBC you should use our forwarder or update the HBC otherwise you wont have that support. I am hoping that now the themers and the translators can catch up with their stuff for the next upcomming official release.
2012-05-06 12:59:58 +02:00
uint8_t *glyphData = (uint8_t *) MEM2_alloc(glyphSize);
memset(glyphData, 0x00, glyphSize);
uint8_t *src = (uint8_t *)bmp->buffer;
uint8_t *dst = glyphData;
2020-12-12 22:35:12 +01:00
// Old FreeType uses int32_t and new versions use uint32_t
int64_t pos, x1, y1, x, y;
2020-12-12 22:35:12 +01:00
for(y1 = 0; y1 < (int64_t)bmp->rows; y1 += 8)
{
2020-12-12 22:35:12 +01:00
for(x1 = 0; x1 < (int64_t)bmp->width; x1 += 8)
{
for(y = y1; y < (y1 + 8); y++)
{
for(x = x1; x < (x1 + 8); x += 2, dst++)
{
2020-12-12 22:35:12 +01:00
if(x >= (int64_t)bmp->width || y >= (int64_t)bmp->rows)
continue;
pos = y * bmp->width + x;
*dst = (src[pos] & 0xF0);
2020-12-12 22:35:12 +01:00
if(x+1 < (int64_t)bmp->width)
*dst |= (src[pos + 1] >> 4);
}
}
}
}
DCFlushRange(glyphData, glyphSize);
charData->glyphDataTexture = glyphData;
}
/**
* Determines the x offset of the rendered string.
*
* This routine calculates the x offset of the rendered string based off of a supplied positional format parameter.
*
* @param width Current pixel width of the string.
* @param format Positional format of the string.
*/
2010-09-24 02:48:03 +02:00
int16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format)
{
if (format & FTGX_JUSTIFY_LEFT)
return 0;
else if (format & FTGX_JUSTIFY_CENTER)
return -(width >> 1);
else if (format & FTGX_JUSTIFY_RIGHT) return -width;
return 0;
}
/**
* Determines the y offset of the rendered string.
*
* This routine calculates the y offset of the rendered string based off of a supplied positional format parameter.
*
* @param offset Current pixel offset data of the string.
* @param format Positional format of the string.
*/
2010-09-24 02:48:03 +02:00
int16_t FreeTypeGX::getStyleOffsetHeight(int16_t format, uint16_t pixelSize)
{
map<int16_t, ftgxDataOffset>::iterator itrAlign = ftgxAlign.find(pixelSize);
if (itrAlign == ftgxAlign.end()) return 0;
switch (format & FTGX_ALIGN_MASK)
{
case FTGX_ALIGN_TOP:
return itrAlign->second.ascender;
case FTGX_ALIGN_MIDDLE:
default:
return (itrAlign->second.ascender + itrAlign->second.descender + 1) >> 1;
case FTGX_ALIGN_BOTTOM:
return itrAlign->second.descender;
case FTGX_ALIGN_BASELINE:
return 0;
case FTGX_ALIGN_GLYPH_TOP:
return itrAlign->second.max;
case FTGX_ALIGN_GLYPH_MIDDLE:
return (itrAlign->second.max + itrAlign->second.min + 1) >> 1;
case FTGX_ALIGN_GLYPH_BOTTOM:
return itrAlign->second.min;
}
return 0;
}
/**
* Processes the supplied text string and prints the results at the specified coordinates.
*
* This routine processes each character of the supplied text string, loads the relevant preprocessed bitmap buffer,
* a texture from said buffer, and loads the resultant texture into the EFB.
*
* @param x Screen X coordinate at which to output the text.
* @param y Screen Y coordinate at which to output the text. Note that this value corresponds to the text string origin and not the top or bottom of the glyphs.
* @param text NULL terminated string to output.
* @param color Optional color to apply to the text characters. If not specified default value is ftgxWhite: (GXColor){0xff, 0xff, 0xff, 0xff}
* @param textStyle Flags which specify any styling which should be applied to the rendered string.
* @return The number of characters printed.
*/
2010-09-24 02:48:03 +02:00
uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color,
uint16_t textStyle, uint16_t textWidth, uint16_t widthLimit)
{
if (!text) return 0;
uint16_t fullTextWidth = textWidth > 0 ? textWidth : getWidth(text, pixelSize);
uint16_t x_pos = x, printed = 0;
uint16_t x_offset = 0, y_offset = 0;
GXTexObj glyphTexture;
FT_Vector pairDelta;
if (textStyle & FTGX_JUSTIFY_MASK)
{
x_offset = getStyleOffsetWidth(fullTextWidth, textStyle);
}
if (textStyle & FTGX_ALIGN_MASK)
{
y_offset = getStyleOffsetHeight(textStyle, pixelSize);
}
int i = 0;
while (text[i])
{
if (widthLimit > 0 && (x_pos - x) > widthLimit) break;
ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize);
if (glyphData != NULL)
{
if (ftKerningEnabled && i > 0)
{
FT_Get_Kerning(ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta);
x_pos += pairDelta.x >> 6;
}
GX_InitTexObj(&glyphTexture, glyphData->glyphDataTexture, glyphData->textureWidth, glyphData->textureHeight, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE);
copyTextureToFramebuffer(&glyphTexture, glyphData->textureWidth, glyphData->textureHeight, x_pos + glyphData->renderOffsetX + x_offset, y - glyphData->renderOffsetY + y_offset, z, color);
x_pos += glyphData->glyphAdvanceX;
++printed;
}
++i;
}
if (textStyle & FTGX_STYLE_MASK)
{
getOffset(text, pixelSize, widthLimit);
drawTextFeature(x + x_offset, y + y_offset, z, pixelSize, fullTextWidth, &ftgxAlign[pixelSize], textStyle,
color);
}
return printed;
}
2010-09-24 02:48:03 +02:00
void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width,
ftgxDataOffset *offsetData, uint16_t format, GXColor color)
{
uint16_t featureHeight = pixelSize >> 4 > 0 ? pixelSize >> 4 : 1;
if (format & FTGX_STYLE_UNDERLINE) this->copyFeatureToFramebuffer(width, featureHeight, x, y + 1, z, color);
if (format & FTGX_STYLE_STRIKE) this->copyFeatureToFramebuffer(width, featureHeight, x, y
- ((offsetData->max) >> 1), z, color);
}
/**
* Processes the supplied string and return the width of the string in pixels.
*
* This routine processes each character of the supplied text string and calculates the width of the entire string.
* Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function.
*
* @param text NULL terminated string to calculate.
* @return The width of the text string in pixels.
*/
2010-09-24 02:48:03 +02:00
uint16_t FreeTypeGX::getWidth(const wchar_t *text, int16_t pixelSize)
{
if (!text) return 0;
uint16_t strWidth = 0;
FT_Vector pairDelta;
int i = 0;
while (text[i])
{
ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize);
if (glyphData != NULL)
{
if (ftKerningEnabled && (i > 0))
{
FT_Get_Kerning(ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex,
FT_KERNING_DEFAULT, &pairDelta);
strWidth += pairDelta.x >> 6;
}
strWidth += glyphData->glyphAdvanceX;
}
++i;
}
return strWidth;
}
/**
* Single char width
2010-09-24 02:48:03 +02:00
*/
uint16_t FreeTypeGX::getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar)
{
uint16_t strWidth = 0;
ftgxCharData * glyphData = cacheGlyphData(wChar, pixelSize);
if (glyphData != NULL)
{
if (ftKerningEnabled && prevChar != 0x0000)
{
FT_Vector pairDelta;
FT_Get_Kerning(ftFace, fontData[pixelSize][prevChar].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT,
&pairDelta);
strWidth += pairDelta.x >> 6;
}
strWidth += glyphData->glyphAdvanceX;
}
return strWidth;
}
/**
* Processes the supplied string and return the height of the string in pixels.
*
* This routine processes each character of the supplied text string and calculates the height of the entire string.
* Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function.
*
* @param text NULL terminated string to calculate.
* @return The height of the text string in pixels.
*/
2010-09-24 02:48:03 +02:00
uint16_t FreeTypeGX::getHeight(const wchar_t *text, int16_t pixelSize)
{
getOffset(text, pixelSize);
return ftgxAlign[pixelSize].max - ftgxAlign[pixelSize].min;
}
/**
* Get the maximum offset above and minimum offset below the font origin line.
*
* This function calculates the maximum pixel height above the font origin line and the minimum
* pixel height below the font origin line and returns the values in an addressible structure.
*
* @param text NULL terminated string to calculate.
* @param offset returns the max and min values above and below the font origin line
*
*/
2010-09-24 02:48:03 +02:00
void FreeTypeGX::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit)
{
if (ftgxAlign.find(pixelSize) != ftgxAlign.end()) return;
int16_t strMax = 0, strMin = 9999;
uint16_t currWidth = 0;
int i = 0;
while (text[i])
{
if (widthLimit > 0 && currWidth >= widthLimit) break;
ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize);
if (glyphData != NULL)
{
strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax;
strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin;
currWidth += glyphData->glyphAdvanceX;
}
++i;
}
if (ftPointSize != pixelSize)
{
ftPointSize = pixelSize;
FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize);
}
ftgxAlign[pixelSize].ascender = ftFace->size->metrics.ascender >> 6;
ftgxAlign[pixelSize].descender = ftFace->size->metrics.descender >> 6;
ftgxAlign[pixelSize].max = strMax;
ftgxAlign[pixelSize].min = strMin;
}
/**
* Copies the supplied texture quad to the EFB.
*
* This routine uses the in-built GX quad builder functions to define the texture bounds and location on the EFB target.
*
* @param texObj A pointer to the glyph's initialized texture object.
* @param texWidth The pixel width of the texture object.
* @param texHeight The pixel height of the texture object.
* @param screenX The screen X coordinate at which to output the rendered texture.
* @param screenY The screen Y coordinate at which to output the rendered texture.
* @param color Color to apply to the texture.
*/
2010-09-24 02:48:03 +02:00
void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX,
int16_t screenY, int16_t screenZ, GXColor color)
{
GX_LoadTexObj(texObj, GX_TEXMAP0);
GX_InvalidateTexAll();
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
GX_Begin(GX_QUADS, this->vertexIndex, 4);
GX_Position3s16(screenX, screenY, screenZ);
GX_Color4u8(color.r, color.g, color.b, color.a);
GX_TexCoord2f32(0.0f, 0.0f);
GX_Position3s16(texWidth + screenX, screenY, screenZ);
GX_Color4u8(color.r, color.g, color.b, color.a);
GX_TexCoord2f32(1.0f, 0.0f);
GX_Position3s16(texWidth + screenX, texHeight + screenY, screenZ);
GX_Color4u8(color.r, color.g, color.b, color.a);
GX_TexCoord2f32(1.0f, 1.0f);
GX_Position3s16(screenX, texHeight + screenY, screenZ);
GX_Color4u8(color.r, color.g, color.b, color.a);
GX_TexCoord2f32(0.0f, 1.0f);
GX_End();
}
/**
* Creates a feature quad to the EFB.
*
* This function creates a simple quad for displaying underline or strikeout text styling.
*
* @param featureWidth The pixel width of the quad.
* @param featureHeight The pixel height of the quad.
* @param screenX The screen X coordinate at which to output the quad.
* @param screenY The screen Y coordinate at which to output the quad.
* @param color Color to apply to the texture.
*/
2010-09-24 02:48:03 +02:00
void FreeTypeGX::copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY,
int16_t screenZ, GXColor color)
{
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
GX_Begin(GX_QUADS, this->vertexIndex, 4);
GX_Position3s16(screenX, screenY, screenZ);
GX_Color4u8(color.r, color.g, color.b, color.a);
GX_Position3s16(featureWidth + screenX, screenY, screenZ);
GX_Color4u8(color.r, color.g, color.b, color.a);
GX_Position3s16(featureWidth + screenX, featureHeight + screenY, screenZ);
GX_Color4u8(color.r, color.g, color.b, color.a);
GX_Position3s16(screenX, featureHeight + screenY, screenZ);
GX_Color4u8(color.r, color.g, color.b, color.a);
GX_End();
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
}