diff --git a/HBC/META.XML b/HBC/META.XML index 5b8486e5..085e09cc 100644 --- a/HBC/META.XML +++ b/HBC/META.XML @@ -2,8 +2,8 @@ USB Loader GX USB Loader GX Team - 1.0 r944 - 201009161846 + 1.0 r945 + 201009171347 Loads games from USB-devices USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times. The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller. diff --git a/gui.pnproj b/gui.pnproj index 47a1608a..5f8f37d0 100644 --- a/gui.pnproj +++ b/gui.pnproj @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/source/FontSystem.cpp b/source/FontSystem.cpp new file mode 100644 index 00000000..ac78ee60 --- /dev/null +++ b/source/FontSystem.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include "FreeTypeGX.h" +#include "filelist.h" + +FreeTypeGX * fontSystem = NULL; +static FT_Byte * MainFont = (FT_Byte *) font_ttf; +static u32 MainFontSize = font_ttf_size; + +void ClearFontData() +{ + if(fontSystem) + delete fontSystem; + fontSystem = NULL; + + if(MainFont != (FT_Byte *) font_ttf) + { + if(MainFont != NULL) + delete [] MainFont; + MainFont = (FT_Byte *) font_ttf; + MainFontSize = font_ttf_size; + } +} + +bool SetupDefaultFont(const char *path) +{ + bool result = false; + FILE *pfile = NULL; + + ClearFontData(); + + if(path) + pfile = fopen(path, "rb"); + + if(pfile) + { + fseek(pfile, 0, SEEK_END); + MainFontSize = ftell(pfile); + rewind(pfile); + + MainFont = new (std::nothrow) FT_Byte[MainFontSize]; + if(!MainFont) + { + MainFont = (FT_Byte *) font_ttf; + MainFontSize = font_ttf_size; + } + else + { + fread(MainFont, 1, MainFontSize, pfile); + result = true; + } + fclose(pfile); + } + + fontSystem = new FreeTypeGX(MainFont, MainFontSize); + + return result; +} diff --git a/source/FontSystem.h b/source/FontSystem.h new file mode 100644 index 00000000..e68b43a9 --- /dev/null +++ b/source/FontSystem.h @@ -0,0 +1,32 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef FONTSYSTEM_H_ +#define FONTSYSTEM_H_ + +bool SetupDefaultFont(const char *path); +void ClearFontData(); + +#endif diff --git a/source/FreeTypeGX.cpp b/source/FreeTypeGX.cpp index 31b2294f..747740a6 100644 --- a/source/FreeTypeGX.cpp +++ b/source/FreeTypeGX.cpp @@ -2,7 +2,7 @@ * 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 Tantric, 2009 + * Modified by Dimok, 2010 * * This file is part of FreeTypeGX. * @@ -20,95 +20,64 @@ * along with FreeTypeGX. If not, see . */ -#include -#include #include "FreeTypeGX.h" -#include "settings/cfg.h" - -#include "main.h" - -/*! \struct ftgxCharData_ - * - * Font face character glyph relevant data structure. - */ -typedef struct ftgxCharData_ { - int16_t renderOffsetX; /**< Texture X axis bearing offset. */ - uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */ - uint16_t glyphIndex; /**< Charachter glyph index in the font face. */ - - uint16_t textureWidth; /**< Texture width in pixels/bytes. */ - uint16_t textureHeight; /**< Texture glyph height in pixels/bytes. */ - - int16_t renderOffsetY; /**< Texture Y axis bearing offset. */ - int16_t renderOffsetMax; /**< Texture Y axis bearing maximum value. */ - int16_t renderOffsetMin; /**< Texture Y axis bearing minimum value. */ - - uint32_t* glyphDataTexture; /**< Glyph texture bitmap data buffer. */ -} ftgxCharData; - -/*! \struct ftgxDataOffset_ - * - * Offset structure which hold both a maximum and minimum value. - */ -typedef struct ftgxDataOffset_ { - int16_t ascender; /**< Maximum data offset. */ - int16_t descender; /**< Minimum data offset. */ - int16_t max; /**< Maximum data offset. */ - int16_t min; /**< Minimum data offset. */ -} ftgxDataOffset; +using namespace std; /** - * Default constructor for the FreeTypeGX class. + * Convert a short char string to a wide char string. * - * @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, uint32_t compatibilityMode) -: -ftFace(NULL), -ftFace_fromFile(NULL) -{ - FT_Init_FreeType(&this->ftLibrary); - - this->textureFormat = textureFormat; - this->setVertexFormat(vertexIndex); - this->setCompatibilityMode(compatibilityMode); -} - -/** - * Default destructor for the FreeTypeGX class. - */ -FreeTypeGX::~FreeTypeGX() { - this->unloadFont(); - FT_Done_FreeType(this->ftLibrary); -} - -/** - * Convert a short char sctring to a wide char string. - * - * This routine converts a supplied shot character string into a wide character 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. */ -wchar_t* FreeTypeGX::charToWideChar(const char* strChar) { - wchar_t *strWChar; - strWChar = new(std::nothrow) wchar_t[strlen(strChar) + 1]; - if(!strWChar) return NULL; - // UTF-8 - int bt; - bt = mbstowcs(strWChar, strChar, strlen(strChar)); - if (bt > 0) { - strWChar[bt] = (wchar_t)'\0'; - return strWChar; - } - wchar_t *tempDest = strWChar; - while ((*tempDest++ = *strChar++)); +wchar_t* charToWideChar(const char* strChar) +{ + if(!strChar) + return NULL; - return strWChar; + 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) +{ + ftPointSize = 0; + + FT_Init_FreeType(&ftLibrary); + FT_New_Memory_Face(ftLibrary, (FT_Byte *)fontBuffer, bufferSize, 0, &ftFace); + + setVertexFormat(GX_VTXFMT1); + ftKerningEnabled = FT_HAS_KERNING(ftFace); +} + +/** + * Default destructor for the FreeTypeGX class. + */ +FreeTypeGX::~FreeTypeGX() +{ + unloadFont(); + FT_Done_Face(ftFace); + FT_Done_FreeType(ftLibrary); } /** @@ -120,235 +89,37 @@ wchar_t* FreeTypeGX::charToWideChar(const char* strChar) { * * @param vertexIndex Vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file. */ -void FreeTypeGX::setVertexFormat(uint8_t vertexIndex) { - this->vertexIndex = vertexIndex; - - GX_SetVtxAttrFmt(this->vertexIndex, GX_VA_POS, GX_POS_XY, GX_S16, 0); - GX_SetVtxAttrFmt(this->vertexIndex, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); - GX_SetVtxAttrFmt(this->vertexIndex, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); +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); } -/** - * Sets the TEV and VTX rendering compatibility requirements for the class. - * - * This sets up the default TEV opertion and VTX descriptions rendering values for the class. This ensures that FreeTypeGX - * can remain compatible with external liraries or project code. Certain external libraries or code by design or lack of - * foresight assume that the TEV opertion and VTX descriptions values will remain constant or are always returned to a - * certain value. This will enable compatibility with those libraries and any other code which cannot or will not be changed. - * - * @param compatibilityMode Compatibility descritor (FTGX_COMPATIBILITY_*) as defined in FreeTypeGX.h -*/ -void FreeTypeGX::setCompatibilityMode(uint32_t compatibilityMode) { - this->compatibilityMode = compatibilityMode; -} - -/** - * Sets the TEV operation and VTX descriptor values after texture rendering it complete. - * - * This function calls the GX_SetTevOp and GX_SetVtxDesc functions with the compatibility parameters specified - * in setCompatibilityMode. - */ -void FreeTypeGX::setDefaultMode() { - if (this->compatibilityMode) { - switch (this->compatibilityMode & 0x00FF) { - case FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_MODULATE: - GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); - break; - case FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_DECAL: - GX_SetTevOp(GX_TEVSTAGE0, GX_DECAL); - break; - case FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_BLEND: - GX_SetTevOp(GX_TEVSTAGE0, GX_BLEND); - break; - case FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_REPLACE: - GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE); - break; - case FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_PASSCLR: - GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); - break; - default: - break; - } - - switch (this->compatibilityMode & 0xFF00) { - case FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE: - GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); - break; - case FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_DIRECT: - GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); - break; - case FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_INDEX8: - GX_SetVtxDesc(GX_VA_TEX0, GX_INDEX8); - break; - case FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_INDEX16: - GX_SetVtxDesc(GX_VA_TEX0, GX_INDEX16); - break; - default: - break; - } - } -} - -/** - * 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 fontPath filename with path to load font from file in memory. - * @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(const char* fontPath, const uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll) { - this->unloadFont(); - this->ftPointSize_v = this->ftPointSize_h = 0; - struct stat st; - - if (fontPath && (stat(fontPath, &st)==0)) { - FILE *fontfile = fopen(fontPath, "rb"); - if (fontfile) { - FT_Long ftFace_fromFile_Size; - - fseek(fontfile, 0, SEEK_END); - ftFace_fromFile_Size = ftell(fontfile); - fseek(fontfile, 0, SEEK_SET); - ftFace_fromFile = (uint8_t*)malloc(ftFace_fromFile_Size); - if (ftFace_fromFile != NULL) { - fread(ftFace_fromFile, 1, ftFace_fromFile_Size, fontfile); - FT_New_Memory_Face(this->ftLibrary, ftFace_fromFile, ftFace_fromFile_Size, 0, &this->ftFace); - } - fclose(fontfile); - } - } - if (ftFace_fromFile == NULL) - FT_New_Memory_Face(this->ftLibrary, (FT_Byte *)fontBuffer, bufferSize, 0, &this->ftFace); - - if (pointSize > 0) - changeSize(pointSize); - - this->ftSlot = this->ftFace->glyph; - this->ftKerningEnabled = FT_HAS_KERNING(this->ftFace); - - if (cacheAll) { - return this->cacheGlyphDataComplete(); - } - - return 0; -} - -void FreeTypeGX::unloadFont() { - clearGlyphData(); - - if (this->ftFace) { - FT_Done_Face(this->ftFace); - this->ftFace = NULL; - } - if (this->ftFace_fromFile) { - free(this->ftFace_fromFile); - this->ftFace_fromFile = NULL; - } -} /** * 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::clearGlyphData() { - if (this->fontDatas.size() == 0) - return; +void FreeTypeGX::unloadFont() +{ + if(this->fontData.size() == 0) + return; - GX_DrawDone(); - GX_Flush(); + map >::iterator itr; + map::iterator itr2; - for ( std::map::iterator i = this->fontDatas.begin(); i != this->fontDatas.end(); i++) + for(itr = fontData.begin(); itr != fontData.end(); itr++) { - for ( FTGX_Cache::iterator j = i->second.begin(); j != i->second.end(); j++) - { - free(j->second.glyphDataTexture); - } - i->second.clear(); - } -/* for ( std::map::iterator i = this->fontData.begin(); i != this->fontData.end(); i++) { - free(i->second.glyphDataTexture); - } -*/ - this->fontDatas.clear(); -} + for(itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++) + free(itr2->second.glyphDataTexture); -void FreeTypeGX::changeSize(FT_UInt vPointSize, FT_UInt hPointSize/*=0*/) { - if(hPointSize == 0) hPointSize = vPointSize; - if(vPointSize > 255) vPointSize = 255;// limit to 255 - if(hPointSize > 255) hPointSize = 255; - if(this->ftPointSize_v != vPointSize || this->ftPointSize_h != hPointSize) - { -// this->clearGlyphData(); - this->ftPointSize_v = vPointSize; - this->ftPointSize_h = hPointSize; - FT_Set_Pixel_Sizes(this->ftFace, this->ftPointSize_h, this->ftPointSize_v); + itr->second.clear(); } -} - -/** - * Adjusts the texture data buffer to necessary width for a given texture format. - * - * This routine determines adjusts the given texture width into the required width to hold the necessary texture data for proper alignment. - * - * @param textureWidth The initial guess for the texture width. - * @param textureFormat The texture format to which the data is to be converted. - * @return The correctly adjusted texture width. - */ -uint16_t FreeTypeGX::adjustTextureWidth(uint16_t textureWidth, uint8_t textureFormat) { - uint16_t alignment; - - switch (textureFormat) { - case GX_TF_I4: /* 8x8 Tiles - 4-bit Intensity */ - case GX_TF_I8: /* 8x4 Tiles - 8-bit Intensity */ - case GX_TF_IA4: /* 8x4 Tiles - 4-bit Intensity, , 4-bit Alpha */ - alignment = 8; - break; - - case GX_TF_IA8: /* 4x4 Tiles - 8-bit Intensity, 8-bit Alpha */ - case GX_TF_RGB565: /* 4x4 Tiles - RGB565 Format */ - case GX_TF_RGB5A3: /* 4x4 Tiles - RGB5A3 Format */ - case GX_TF_RGBA8: /* 4x4 Tiles - RGBA8 Dual Cache Line Format */ - default: - alignment = 4; - break; - } - return textureWidth % alignment == 0 ? textureWidth : alignment + textureWidth - (textureWidth % alignment); - -} - -/** - * Adjusts the texture data buffer to necessary height for a given texture format. - * - * This routine determines adjusts the given texture height into the required height to hold the necessary texture data for proper alignment. - * - * @param textureHeight The initial guess for the texture height. - * @param textureFormat The texture format to which the data is to be converted. - * @return The correctly adjusted texture height. - */ -uint16_t FreeTypeGX::adjustTextureHeight(uint16_t textureHeight, uint8_t textureFormat) { - uint16_t alignment; - - switch (textureFormat) { - case GX_TF_I4: /* 8x8 Tiles - 4-bit Intensity */ - alignment = 8; - break; - - case GX_TF_I8: /* 8x4 Tiles - 8-bit Intensity */ - case GX_TF_IA4: /* 8x4 Tiles - 4-bit Intensity, , 4-bit Alpha */ - case GX_TF_IA8: /* 4x4 Tiles - 8-bit Intensity, 8-bit Alpha */ - case GX_TF_RGB565: /* 4x4 Tiles - RGB565 Format */ - case GX_TF_RGB5A3: /* 4x4 Tiles - RGB5A3 Format */ - case GX_TF_RGBA8: /* 4x4 Tiles - RGBA8 Dual Cache Line Format */ - default: - alignment = 4; - break; - } - return textureHeight % alignment == 0 ? textureHeight : alignment + textureHeight - (textureHeight % alignment); + fontData.clear(); + ftgxAlign.clear(); } /** @@ -360,43 +131,66 @@ uint16_t FreeTypeGX::adjustTextureHeight(uint16_t textureHeight, uint8_t texture * @param charCode The requested glyph's character code. * @return A pointer to the allocated font structure. */ -ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode) -{ - FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8]; - return cacheGlyphData(charCode, fontData); -} -ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode, FTGX_Cache &fontData) +ftgxCharData * FreeTypeGX::cacheGlyphData(wchar_t charCode, int16_t pixelSize) { + map >::iterator itr; + map::iterator itr2; + + itr = fontData.find(pixelSize); + if(itr != fontData.end()) + { + itr2 = itr->second.find(charCode); + + if(itr2 != itr->second.end()) + { + return &itr2->second; + } + } + FT_UInt gIndex; uint16_t textureWidth = 0, textureHeight = 0; - gIndex = FT_Get_Char_Index( this->ftFace, charCode ); - if (!FT_Load_Glyph(this->ftFace, gIndex, FT_LOAD_DEFAULT )) { - FT_Render_Glyph( this->ftSlot, FT_RENDER_MODE_NORMAL ); + if(ftPointSize != pixelSize) + { + ftPointSize = pixelSize; + FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize); - if (this->ftSlot->format == FT_GLYPH_FORMAT_BITMAP) { - FT_Bitmap *glyphBitmap = &this->ftSlot->bitmap; - - textureWidth = adjustTextureWidth(glyphBitmap->width, this->textureFormat); - textureHeight = adjustTextureHeight(glyphBitmap->rows, this->textureFormat); - - fontData[charCode] = (ftgxCharData) { - this->ftSlot->bitmap_left, - this->ftSlot->advance.x >> 6, - gIndex, - textureWidth, - textureHeight, - this->ftSlot->bitmap_top, - this->ftSlot->bitmap_top, - glyphBitmap->rows - this->ftSlot->bitmap_top, - NULL - }; - this->loadGlyphData(glyphBitmap, &fontData[charCode]); - - return &fontData[charCode]; - } + //!Cache ascender and decender as well + map::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 = glyphBitmap->width + (4 - glyphBitmap->width % 4) % 4; + textureHeight = glyphBitmap->rows + (4 - glyphBitmap->rows % 4) % 4; + + 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; } @@ -406,20 +200,19 @@ ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode, FTGX_Cache &fontData) * 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. */ -uint16_t FreeTypeGX::cacheGlyphDataComplete() { - uint16_t i = 0; - FT_UInt gIndex; - FT_ULong charCode = FT_Get_First_Char( this->ftFace, &gIndex ); - while ( gIndex != 0 ) { +uint16_t FreeTypeGX::cacheGlyphDataComplete(int16_t pixelSize) +{ + uint32_t i = 0; + FT_UInt gIndex; - if (this->cacheGlyphData(charCode) != NULL) { - i++; - } - - charCode = FT_Get_Next_Char( this->ftFace, charCode, &gIndex ); - } - - return i; + 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); } /** @@ -430,45 +223,38 @@ uint16_t FreeTypeGX::cacheGlyphDataComplete() { * * @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. + * + * + * Optimized for RGBA8 use by Dimok. */ -void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData) { +void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData) +{ + int length = ((((charData->textureWidth+3)>>2)*((charData->textureHeight+3)>>2)*32*2 + 31) & ~31); - uint32_t *glyphData = (uint32_t *)memalign(32, charData->textureWidth * charData->textureHeight * 4); - memset(glyphData, 0x00, charData->textureWidth * charData->textureHeight * 4); + uint8_t * glyphData = (uint8_t *) memalign(32, length); + if(!glyphData) + return; - for (uint16_t imagePosY = 0; imagePosY < bmp->rows; imagePosY++) { - for (uint16_t imagePosX = 0; imagePosX < bmp->width; imagePosX++) { - uint32_t pixel = (uint32_t) bmp->buffer[imagePosY * bmp->width + imagePosX]; - glyphData[imagePosY * charData->textureWidth + imagePosX] = 0x00000000 | (pixel << 24) | (pixel << 16) | (pixel << 8) | pixel; - } - } + memset(glyphData, 0x00, length); - switch (this->textureFormat) { - case GX_TF_I4: - charData->glyphDataTexture = Metaphrasis::convertBufferToI4(glyphData, charData->textureWidth, charData->textureHeight); - break; - case GX_TF_I8: - charData->glyphDataTexture = Metaphrasis::convertBufferToI8(glyphData, charData->textureWidth, charData->textureHeight); - break; - case GX_TF_IA4: - charData->glyphDataTexture = Metaphrasis::convertBufferToIA4(glyphData, charData->textureWidth, charData->textureHeight); - break; - case GX_TF_IA8: - charData->glyphDataTexture = Metaphrasis::convertBufferToIA8(glyphData, charData->textureWidth, charData->textureHeight); - break; - case GX_TF_RGB565: - charData->glyphDataTexture = Metaphrasis::convertBufferToRGB565(glyphData, charData->textureWidth, charData->textureHeight); - break; - case GX_TF_RGB5A3: - charData->glyphDataTexture = Metaphrasis::convertBufferToRGB5A3(glyphData, charData->textureWidth, charData->textureHeight); - break; - case GX_TF_RGBA8: - default: - charData->glyphDataTexture = Metaphrasis::convertBufferToRGBA8(glyphData, charData->textureWidth, charData->textureHeight); - break; - } + uint8_t *src = (uint8_t *)bmp->buffer; + uint32_t offset; - free(glyphData); + for (int imagePosY = 0; imagePosY < bmp->rows; ++imagePosY) + { + for (int imagePosX = 0; imagePosX < bmp->width; ++imagePosX) + { + offset = ((((imagePosY >> 2) * (charData->textureWidth >> 2) + (imagePosX >> 2)) << 5) + ((imagePosY & 3) << 2) + (imagePosX & 3)) << 1; + glyphData[offset] = *src; + glyphData[offset+1] = *src; + glyphData[offset+32] = *src; + glyphData[offset+33] = *src; + ++src; + } + } + DCFlushRange(glyphData, length); + + charData->glyphDataTexture = glyphData; } /** @@ -479,21 +265,15 @@ void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData) { * @param width Current pixel width of the string. * @param format Positional format of the string. */ -int16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format) { - - switch (format & FTGX_JUSTIFY_MASK) { - case FTGX_JUSTIFY_LEFT: - return 0; - - default: - case FTGX_JUSTIFY_CENTER: - return -(width >> 1); - - case FTGX_JUSTIFY_RIGHT: - return -width; - } - - return 0; +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; } /** @@ -504,32 +284,37 @@ int16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format) { * @param offset Current pixel offset data of the string. * @param format Positional format of the string. */ -int16_t FreeTypeGX::getStyleOffsetHeight(ftgxDataOffset *offset, uint16_t format) { - switch (format & FTGX_ALIGN_MASK) { - case FTGX_ALIGN_TOP: - return offset->ascender; - - default: - case FTGX_ALIGN_MIDDLE: - return (offset->ascender + offset->descender + 1) >> 1; - - case FTGX_ALIGN_BOTTOM: - return offset->descender; - - case FTGX_ALIGN_BASELINE: +int16_t FreeTypeGX::getStyleOffsetHeight(int16_t format, uint16_t pixelSize) +{ + map::iterator itrAlign = ftgxAlign.find(pixelSize); + if(itrAlign == ftgxAlign.end()) return 0; - case FTGX_ALIGN_GLYPH_TOP: - return offset->max; + switch(format & FTGX_ALIGN_MASK) + { + case FTGX_ALIGN_TOP: + return itrAlign->second.ascender; - case FTGX_ALIGN_GLYPH_MIDDLE: - return (offset->max + offset->min + 1) >> 1; + case FTGX_ALIGN_MIDDLE: + default: + return (itrAlign->second.ascender + itrAlign->second.descender + 1) >> 1; - case FTGX_ALIGN_GLYPH_BOTTOM: - return offset->min; - } + case FTGX_ALIGN_BOTTOM: + return itrAlign->second.descender; - return 0; + 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; } /** @@ -545,95 +330,70 @@ int16_t FreeTypeGX::getStyleOffsetHeight(ftgxDataOffset *offset, uint16_t format * @param textStyle Flags which specify any styling which should be applied to the rendered string. * @return The number of characters printed. */ -uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, const wchar_t *text, GXColor color, uint16_t textStyle) { - uint16_t strLength = wcslen(text); - uint16_t x_pos = x, printed = 0; - uint16_t x_offset = 0, y_offset = 0; - GXTexObj glyphTexture; - FT_Vector pairDelta; - ftgxDataOffset offset; - FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8]; - - if (textStyle & FTGX_JUSTIFY_MASK) { - x_offset = this->getStyleOffsetWidth(this->getWidth(text), textStyle); - } - if (textStyle & FTGX_ALIGN_MASK) { - y_offset = this->getStyleOffsetHeight(this->getOffset(text, &offset), textStyle); - } +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; - for (uint16_t i = 0; i < strLength; i++) { + 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; - ftgxCharData* glyphData = NULL; - if ( fontData.find(text[i]) != fontData.end() ) { - glyphData = &fontData[text[i]]; - } else { - glyphData = this->cacheGlyphData(text[i], fontData); - } + if(textStyle & FTGX_JUSTIFY_MASK) + { + x_offset = getStyleOffsetWidth(fullTextWidth, textStyle); + } + if(textStyle & FTGX_ALIGN_MASK) + { + y_offset = getStyleOffsetHeight(textStyle, pixelSize); + } - if (glyphData != NULL) { + int i = 0; - if (this->ftKerningEnabled && i) { - FT_Get_Kerning( this->ftFace, fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta ); - x_pos += pairDelta.x >> 6; - } + while (text[i]) + { + if(widthLimit > 0 && (x_pos-x) > widthLimit) + break; - GX_InitTexObj(&glyphTexture, glyphData->glyphDataTexture, glyphData->textureWidth, glyphData->textureHeight, this->textureFormat, GX_CLAMP, GX_CLAMP, GX_FALSE); - this->copyTextureToFramebuffer(&glyphTexture, glyphData->textureWidth, glyphData->textureHeight, x_pos + glyphData->renderOffsetX + x_offset, y - glyphData->renderOffsetY + y_offset, color); + ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize); - x_pos += glyphData->glyphAdvanceX; - printed++; - } - } + 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; + } - if (textStyle & FTGX_STYLE_MASK) { - this->drawTextFeature(x + x_offset, y + y_offset, this->getWidth(text), this->getOffset(text, &offset), textStyle, color); - } + GX_InitTexObj(&glyphTexture, glyphData->glyphDataTexture, glyphData->textureWidth, glyphData->textureHeight, GX_TF_RGBA8, 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); - return printed; + 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; } +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; -void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color) { - uint16_t featureHeight = this->ftPointSize_v >> 4 > 0 ? this->ftPointSize_v >> 4 : 1; + if (format & FTGX_STYLE_UNDERLINE) + this->copyFeatureToFramebuffer(width, featureHeight, x, y + 1, z, color); - if (format & FTGX_STYLE_UNDERLINE ) { - switch (format & FTGX_ALIGN_MASK) { - /* - case FTGX_ALIGN_TOP: - this->copyFeatureToFramebuffer(width, featureHeight, x, y + offsetData->max + 1, color); - break; - case FTGX_ALIGN_MIDDLE: - this->copyFeatureToFramebuffer(width, featureHeight, x, y + ((offsetData->max - offsetData->min + 1) >> 1), color); - break; - case FTGX_ALIGN_BOTTOM: - this->copyFeatureToFramebuffer(width, featureHeight, x, y - offsetData->min, color); - break; - */ - default: - this->copyFeatureToFramebuffer(width, featureHeight, x, y + 1, color); - break; - } - } - - if (format & FTGX_STYLE_STRIKE ) { - switch (format & FTGX_ALIGN_MASK) { - /* - case FTGX_ALIGN_TOP: - this->copyFeatureToFramebuffer(width, featureHeight, x, y + ((offsetData->max - offsetData->min + 1) >> 1), color); - break; - case FTGX_ALIGN_MIDDLE: - this->copyFeatureToFramebuffer(width, featureHeight, x, y, color); - break; - case FTGX_ALIGN_BOTTOM: - this->copyFeatureToFramebuffer(width, featureHeight, x, y - ((offsetData->max + offsetData->min) >> 1), color); - break; - */ - default: -// this->copyFeatureToFramebuffer(width, featureHeight, x, y - ((offsetData->max - offsetData->min) >> 1), color); - this->copyFeatureToFramebuffer(width, featureHeight, x, y - ((offsetData->max) >> 1), color); - break; - } - } + if (format & FTGX_STYLE_STRIKE) + this->copyFeatureToFramebuffer(width, featureHeight, x, y - ((offsetData->max) >> 1), z, color); } /** @@ -645,34 +405,55 @@ void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, uint16_t width, ftgxDataO * @param text NULL terminated string to calculate. * @return The width of the text string in pixels. */ -uint16_t FreeTypeGX::getWidth(const wchar_t *text) { - uint16_t strLength = wcslen(text); - uint16_t strWidth = 0; - FT_Vector pairDelta; - FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8]; +uint16_t FreeTypeGX::getWidth(const wchar_t *text, int16_t pixelSize) +{ + if(!text) + return 0; - for (uint16_t i = 0; i < strLength; i++) { + uint16_t strWidth = 0; + FT_Vector pairDelta; - ftgxCharData* glyphData = NULL; - if ( fontData.find(text[i]) != fontData.end() ) { - glyphData = &fontData[text[i]]; - } else { - glyphData = this->cacheGlyphData(text[i], fontData); - } + int i = 0; + while (text[i]) + { + ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize); - if (glyphData != NULL) { - if (this->ftKerningEnabled && (i > 0)) { - FT_Get_Kerning( this->ftFace, fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta ); - strWidth += pairDelta.x >> 6; - } + 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; - } - } - - return strWidth; + strWidth += glyphData->glyphAdvanceX; + } + ++i; + } + return strWidth; } +/** + * Single char width +*/ +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. @@ -683,11 +464,11 @@ uint16_t FreeTypeGX::getWidth(const wchar_t *text) { * @param text NULL terminated string to calculate. * @return The height of the text string in pixels. */ -uint16_t FreeTypeGX::getHeight(const wchar_t *text) { - ftgxDataOffset offset; - this->getOffset(text, &offset); +uint16_t FreeTypeGX::getHeight(const wchar_t *text, int16_t pixelSize) +{ + getOffset(text, pixelSize); - return offset.max - offset.min; + return ftgxAlign[pixelSize].max - ftgxAlign[pixelSize].min; } /** @@ -700,33 +481,45 @@ uint16_t FreeTypeGX::getHeight(const wchar_t *text) { * @param offset returns the max and min values above and below the font origin line * */ -ftgxDataOffset* FreeTypeGX::getOffset(const wchar_t *text, ftgxDataOffset* offset) { - uint16_t strLength = wcslen(text); - int16_t strMax = 0, strMin = 9999; - FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8]; - - for (uint16_t i = 0; i < strLength; i++) { +void FreeTypeGX::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit) +{ + if(ftgxAlign.find(pixelSize) != ftgxAlign.end()) + return; - ftgxCharData* glyphData = NULL; - if ( fontData.find(text[i]) != fontData.end() ) { - glyphData = &fontData[text[i]]; - } else { - glyphData = this->cacheGlyphData(text[i], fontData); - } + int16_t strMax = 0, strMin = 9999; + uint16_t currWidth = 0; - if (glyphData != NULL) { - strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax; - strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin; - } - } - offset->ascender = this->ftFace->size->metrics.ascender>>6; - offset->descender = this->ftFace->size->metrics.descender>>6; - offset->max = strMax; - offset->min = strMin; - return offset; + 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. * @@ -739,33 +532,34 @@ ftgxDataOffset* FreeTypeGX::getOffset(const wchar_t *text, ftgxDataOffset* offse * @param screenY The screen Y coordinate at which to output the rendered texture. * @param color Color to apply to the texture. */ -void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, GXColor color) { +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_LoadTexObj(texObj, GX_TEXMAP0); - GX_InvalidateTexAll(); + GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); + GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT); - GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); - GX_SetVtxDesc (GX_VA_TEX0, 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_Begin(GX_QUADS, this->vertexIndex, 4); - GX_Position2s16(screenX, screenY); - 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_Position2s16(texWidth + screenX, screenY); - 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_Position2s16(texWidth + screenX, texHeight + screenY); - 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(); - GX_Position2s16(screenX, texHeight + screenY); - GX_Color4u8(color.r, color.g, color.b, color.a); - GX_TexCoord2f32(0.0f, 1.0f); - GX_End(); - - this->setDefaultMode(); + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); } /** @@ -779,24 +573,25 @@ void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 te * @param screenY The screen Y coordinate at which to output the quad. * @param color Color to apply to the texture. */ -void FreeTypeGX::copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, GXColor color) { +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_TEX0, GX_NONE); - GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR); - 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_Begin(GX_QUADS, this->vertexIndex, 4); - GX_Position2s16(screenX, screenY); - 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_Position2s16(featureWidth + screenX, screenY); - 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_Position2s16(featureWidth + screenX, featureHeight + screenY); - 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_Position2s16(screenX, featureHeight + screenY); - GX_Color4u8(color.r, color.g, color.b, color.a); - GX_End(); - - this->setDefaultMode(); + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); } diff --git a/source/FreeTypeGX.h b/source/FreeTypeGX.h index 4fa2b17c..8b2f7a13 100644 --- a/source/FreeTypeGX.h +++ b/source/FreeTypeGX.h @@ -2,7 +2,7 @@ * 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 Tantric, 2009 + * Modified by Dimok, 2010 * * This file is part of FreeTypeGX. * @@ -20,134 +20,6 @@ * along with FreeTypeGX. If not, see . */ -/** \mainpage FreeTypeGX - * - * \section sec_intro Introduction - * - * FreeTypeGX is a wrapper class for libFreeType which renders a compiled FreeType parsable font into a GX texture for Wii homebrew development. - *
- * FreeTypeGX is written in C++ and makes use of a selectable pre-buffered or buffer-on-demand methodology to allow fast and efficient printing of text to the EFB. - *

- * This library was developed in-full by Armin Tamzarian with the support of developers in \#wiibrew on EFnet. - * - * \section sec_installation_source Installation (Source Code) - * - * -# Ensure that you have the libFreeType Wii library installed in your development environment with the library added to your Makefile where appropriate. - * -# Ensure that you have the Metaphrasis library installed in your development environment with the library added to your Makefile where appropriate. - * -# Extract the FreeTypeGX archive. - * -# Copy the contents of the src directory into your project's development path. - * -# Include the FreeTypeGX header file in your code using syntax such as the following: - * \code - * #include "FreeTypeGX.h" - * \endcode - * - * \section sec_installation_library Installation (Library) - * - * -# Ensure that you have the libFreeType Wii library installed in your development environment with the library added to your Makefile where appropriate. - * -# Ensure that you have the Metaphrasis library installed in your development environment with the library added to your Makefile where appropriate. - * -# Extract the FreeTypeGX archive. - * -# Copy the contents of the lib directory into your devKitPro/libogc directory. - * -# Include the FreeTypeGX header file in your code using syntax such as the following: - * \code - * #include "FreeTypeGX.h" - * \endcode - * - * \section sec_freetypegx_prerequisites FreeTypeGX Prerequisites - * - * Before you begin using FreeTypeGX in your project you must ensure that the desired font in compiled into your project. For this example I will assume you are building your project with a Makefile using devKitPro evironment and are attempting to include a font whose filename is rursus_compact_mono.ttf. - * - * -# Copy the font into a directory which will be processed by the project's Makefile. If you are unsure about where you should place your font just copy the it into your project's source directory. - * \n\n - * -# Modify the Makefile to convert the font into an object file: - * \code - * %.ttf.o : %.ttf - * @echo $(notdir $<) - * $(bin2o) - * \endcode - * \n - * -# Include the font object's generated header file in your source code: - * \code - * #include "rursus_compact_mono_ttf.h" - * \endcode - * This header file defines the two variables that you will need for use within your project: - * \code - * extern const u8 rursus_compact_mono_ttf[]; A pointer to the font buffer within the compiled project. - * extern const u32 rursus_compact_mono_ttf_size; The size of the font's buffer in bytes. - * \endcode - * - * \section sec_freetypegx_usage FreeTypeGX Usage - * - * -# Within the file you included the FreeTypeGX.h header create an instance object of the FreeTypeGX class: - * \code - * FreeTypeGX *freeTypeGX = new FreeTypeGX(); - * \endcode - * Alternately you can specify a texture format to which you would like to render the font characters. Note that the default value for this parameter is GX_TF_RGBA8. - * \code - * FreeTypeGX *freeTypeGX = new FreeTypeGX(GX_TF_RGB565); - * \endcode - * Furthermore, you can also specify a vertex format index to avoid conflicts with concurrent libraries or other systems. Note that the default value for this parameter is GX_VTXFMT1. - * \code - * FreeTypeGX *freeTypeGX = new FreeTypeGX(GX_TF_RGB565, GX_VTXFMT1); - * \endcode - * \n - * Currently supported textures are: - * \li GX_TF_I4 - * \li GX_TF_I8 - * \li GX_TF_IA4 - * \li GX_TF_IA8 - * \li GX_TF_RGB565 - * \li GX_TF_RGB5A3 - * \li GX_TF_RGBA8 - * - * \n - * -# Using the allocated FreeTypeGX instance object call the loadFont function to load the font from the compiled buffer and specify the desired point size. Note that this function can be called multiple times to load a new: - * \code - * freeTypeGX->loadFont(rursus_compact_mono_ttf, rursus_compact_mono_ttf_size, 64); - * \endcode - * Alternately you can specify a flag which will load and cache all available font glyphs immidiately. Note that on large font sets enabling this feature could take a significant amount of time. - * \code - * freeTypeGX->loadFont(rursus_compact_mono_ttf, rursus_compact_mono_ttf_size, 64, true); - * \endcode - * \n - * -# If necessary you can enable compatibility modes with concurrent libraries or systems. For more information on this feature see the documentation for setCompatibilityMode: - * \code - * freeTypeGX->setCompatibilityMode(FTGX_COMPATIBILITY_GRRLIB); - * \endcode - * -# Using the allocated FreeTypeGX instance object call the drawText function to print a string at the specified screen X and Y coordinates to the current EFB: - * \code - * freeTypeGX->drawText(10, 25, _TEXT("FreeTypeGX Rocks!")); - * \endcode - * Alternately you can specify a GXColor object you would like to apply to the printed characters: - * \code - * freeTypeGX->drawText(10, 25, _TEXT("FreeTypeGX Rocks!"), - * (GXColor){0xff, 0xee, 0xaa, 0xff}); - * \endcode - * Furthermore you can also specify a group of styling parameters which will modify the positioning or style of the text: - * \code - * freeTypeGX->drawText(10, 25, _TEXT("FreeTypeGX Rocks!"), - * (GXColor){0xff, 0xee, 0xaa, 0xff}, - * FTGX_JUSTIFY_CENTER | FTGX_ALIGN_BOTTOM | FTGX_STYLE_UNDERLINE); - * \endcode - * \n - * Currently style parameters are: - * \li FTGX_JUSTIFY_LEFT - * \li FTGX_JUSTIFY_CENTER - * \li FTGX_JUSTIFY_RIGHT - * \li FTGX_ALIGN_TOP - * \li FTGX_ALIGN_MIDDLE - * \li FTGX_ALIGN_BOTTOM - * \li FTGX_STYLE_UNDERLINE - * \li FTGX_STYLE_STRIKE - * - * \section sec_license License - * - * FreeTypeGX is distributed under the GNU Lesser General Public License. - * - * \section sec_contact Contact - * - * If you have any suggestions, questions, or comments regarding this library feel free to e-mail me at tamzarian1989 [at] gmail [dawt] com. - */ - #ifndef FREETYPEGX_H_ #define FREETYPEGX_H_ @@ -155,58 +27,69 @@ #include #include FT_FREETYPE_H #include FT_BITMAP_H -#include "Metaphrasis.h" #include #include +#include #include -/*! forward deklaration of private structures +/*! \struct ftgxCharData_ * + * Font face character glyph relevant data structure. */ +typedef struct ftgxCharData_ { + int16_t renderOffsetX; /**< Texture X axis bearing offset. */ + uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */ + uint32_t glyphIndex; /**< Charachter glyph index in the font face. */ + + uint16_t textureWidth; /**< Texture width in pixels/bytes. */ + uint16_t textureHeight; /**< Texture glyph height in pixels/bytes. */ + + int16_t renderOffsetY; /**< Texture Y axis bearing offset. */ + int16_t renderOffsetMax; /**< Texture Y axis bearing maximum value. */ + int16_t renderOffsetMin; /**< Texture Y axis bearing minimum value. */ + + uint8_t* glyphDataTexture; /**< Glyph texture bitmap data buffer. */ +} ftgxCharData; + +/*! \struct ftgxDataOffset_ + * + * Offset structure which hold both a maximum and minimum value. + */ +typedef struct ftgxDataOffset_ { + int16_t ascender; /**< Maximum data offset. */ + int16_t descender; /**< Minimum data offset. */ + int16_t max; /**< Maximum data offset. */ + int16_t min; /**< Minimum data offset. */ +} ftgxDataOffset; + typedef struct ftgxCharData_ ftgxCharData; typedef struct ftgxDataOffset_ ftgxDataOffset; #define _TEXT(t) L ## t /**< Unicode helper macro. */ -#define FTGX_NULL 0x0000 -#define FTGX_JUSTIFY_LEFT 0x0001 -#define FTGX_JUSTIFY_CENTER 0x0002 -#define FTGX_JUSTIFY_RIGHT 0x0003 -#define FTGX_JUSTIFY_MASK 0x000f +#define FTGX_NULL 0x0000 +#define FTGX_JUSTIFY_LEFT 0x0001 +#define FTGX_JUSTIFY_CENTER 0x0002 +#define FTGX_JUSTIFY_RIGHT 0x0004 +#define FTGX_JUSTIFY_MASK 0x000f -#define FTGX_ALIGN_TOP 0x0010 -#define FTGX_ALIGN_MIDDLE 0x0020 -#define FTGX_ALIGN_BOTTOM 0x0030 -#define FTGX_ALIGN_BASELINE 0x0040 -#define FTGX_ALIGN_GLYPH_TOP 0x0050 -#define FTGX_ALIGN_GLYPH_MIDDLE 0x0060 -#define FTGX_ALIGN_GLYPH_BOTTOM 0x0070 -#define FTGX_ALIGN_MASK 0x00f0 +#define FTGX_ALIGN_TOP 0x0010 +#define FTGX_ALIGN_MIDDLE 0x0020 +#define FTGX_ALIGN_BOTTOM 0x0040 +#define FTGX_ALIGN_BASELINE 0x0080 +#define FTGX_ALIGN_GLYPH_TOP 0x0100 +#define FTGX_ALIGN_GLYPH_MIDDLE 0x0200 +#define FTGX_ALIGN_GLYPH_BOTTOM 0x0400 +#define FTGX_ALIGN_MASK 0x0ff0 -#define FTGX_STYLE_UNDERLINE 0x0100 -#define FTGX_STYLE_STRIKE 0x0200 -#define FTGX_STYLE_MASK 0x0f00 +#define FTGX_STYLE_UNDERLINE 0x1000 +#define FTGX_STYLE_STRIKE 0x2000 +#define FTGX_STYLE_MASK 0xf000 -#define FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_MODULATE 0X0001 -#define FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_DECAL 0X0002 -#define FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_BLEND 0X0004 -#define FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_REPLACE 0X0008 -#define FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_PASSCLR 0X0010 +const GXColor ftgxWhite = (GXColor){0xff, 0xff, 0xff, 0xff}; /**< Constant color value used only to sanitize Doxygen documentation. */ -#define FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE 0X0100 -#define FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_DIRECT 0X0200 -#define FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_INDEX8 0X0400 -#define FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_INDEX16 0X0800 - -#define FTGX_COMPATIBILITY_NONE 0x0000 -#define FTGX_COMPATIBILITY_GRRLIB FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_PASSCLR | FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE -#define FTGX_COMPATIBILITY_LIBWIISPRITE FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_MODULATE | FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_DIRECT - -const GXColor ftgxWhite = (GXColor) { - 0xff, 0xff, 0xff, 0xff -} -; /**< Constant color value used only to sanitize Doxygen documentation. */ +wchar_t* charToWideChar(const char* p); /*! \class FreeTypeGX * \brief Wrapper class for the libFreeType library with GX rendering. @@ -217,59 +100,43 @@ const GXColor ftgxWhite = (GXColor) { * a specified texture format. Rendering of the data to the EFB is accomplished through the application of high performance * GX texture functions resulting in high throughput of string rendering. */ -typedef std::map FTGX_Cache; -class FreeTypeGX { +class FreeTypeGX +{ + private: + FT_Library ftLibrary; /**< FreeType FT_Library instance. */ + FT_Face ftFace; /**< FreeType reusable FT_Face typographic object. */ + int16_t ftPointSize; /**< Current set size of the rendered font. */ + bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */ + uint8_t vertexIndex; /**< Vertex format descriptor index. */ + std::map > fontData; /**< Map which holds the glyph data structures for the corresponding characters in one size. */ + std::map ftgxAlign; /**< Map which holds the ascender and decender for different sizes. */ -private: - FT_Library ftLibrary; /**< FreeType FT_Library instance. */ - FT_Face ftFace; /**< FreeType reusable FT_Face typographic object. */ - FT_Byte *ftFace_fromFile; - FT_GlyphSlot ftSlot; /**< FreeType reusable FT_GlyphSlot glyph container object. */ - FT_UInt ftPointSize_v; /**< Requested size of the rendered font. */ - FT_UInt ftPointSize_h; /**< Requested size of the rendered font. */ - bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */ + int16_t getStyleOffsetWidth(uint16_t width, uint16_t format); + int16_t getStyleOffsetHeight(int16_t format, uint16_t pixelSize); - uint8_t textureFormat; /**< Defined texture format of the target EFB. */ - uint8_t vertexIndex; /**< Vertex format descriptor index. */ - uint32_t compatibilityMode; /**< Compatibility mode for default tev operations and vertex descriptors. */ -// FTGX_Cache fontData; /**< Map which holds the glyph data structures for the corresponding characters. */ - std::map fontDatas; + void unloadFont(); + ftgxCharData *cacheGlyphData(wchar_t charCode, int16_t pixelSize); + uint16_t cacheGlyphDataComplete(int16_t pixelSize); + void loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData); - static uint16_t adjustTextureWidth(uint16_t textureWidth, uint8_t textureFormat); - static uint16_t adjustTextureHeight(uint16_t textureHeight, uint8_t textureFormat); + void setDefaultMode(); - static int16_t getStyleOffsetWidth(uint16_t width, uint16_t format); - static int16_t getStyleOffsetHeight(ftgxDataOffset *offset, uint16_t format); + void drawTextFeature(int16_t x, int16_t y,int16_t z, int16_t pixelSize, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color); + void copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color); + void copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color); - void unloadFont(); - void clearGlyphData(); - ftgxCharData *cacheGlyphData(wchar_t charCode); - ftgxCharData *cacheGlyphData(wchar_t charCode, FTGX_Cache &fontData); - uint16_t cacheGlyphDataComplete(); - void loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData); + public: + FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize); + ~FreeTypeGX(); - void setDefaultMode(); + void setVertexFormat(uint8_t vertexIndex); - void drawTextFeature(int16_t x, int16_t y, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color); - void copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, GXColor color); - void copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, GXColor color); + uint16_t drawText(int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL, uint16_t textWidth = 0, uint16_t widthLimit = 0); -public: - FreeTypeGX(uint8_t textureFormat = GX_TF_RGBA8, uint8_t vertexIndex = GX_VTXFMT1, uint32_t compatibilityMode = FTGX_COMPATIBILITY_NONE); - ~FreeTypeGX(); - - static wchar_t* charToWideChar(const char* p); - void setVertexFormat(uint8_t vertexIndex); - void setCompatibilityMode(uint32_t compatibilityMode); - - uint16_t loadFont(const char* fontPath, const uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll = false); - void changeSize(FT_UInt vPointSize, FT_UInt hPointSize=0); - - uint16_t drawText(int16_t x, int16_t y, const wchar_t *text, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL); - - uint16_t getWidth(const wchar_t *text); - uint16_t getHeight(const wchar_t *text); - ftgxDataOffset* getOffset(const wchar_t *text, ftgxDataOffset* offset); + uint16_t getWidth(const wchar_t *text, int16_t pixelSize); + uint16_t getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar = 0x0000); + uint16_t getHeight(const wchar_t *text, int16_t pixelSize); + void getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit = 0); }; #endif /* FREETYPEGX_H_ */ diff --git a/source/cheats/cheatmenu.cpp b/source/cheats/cheatmenu.cpp index 3e751079..43b0db2a 100644 --- a/source/cheats/cheatmenu.cpp +++ b/source/cheats/cheatmenu.cpp @@ -89,7 +89,7 @@ int CheatMenu(const char * gameID) { GuiText titleTxt(c.getGameName().c_str(), 28, (GXColor) {0, 0, 0, 255}); titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); - titleTxt.SetMaxWidth(350, GuiText::SCROLL); + titleTxt.SetMaxWidth(350, SCROLL_HORIZONTAL); titleTxt.SetPosition(12,40); for (int i = 0; i <= cntcheats; i++) { diff --git a/source/homebrewboot/HomebrewBrowse.cpp b/source/homebrewboot/HomebrewBrowse.cpp index 1a21c8e7..755c16e2 100644 --- a/source/homebrewboot/HomebrewBrowse.cpp +++ b/source/homebrewboot/HomebrewBrowse.cpp @@ -191,15 +191,15 @@ int MenuHomebrewBrowse() { GuiImage MainButton1Img(&MainButtonImgData); GuiImage MainButton1ImgOver(&MainButtonImgOverData); GuiText MainButton1Txt(MainButtonText, 18, (GXColor) {0, 0, 0, 255}); - MainButton1Txt.SetMaxWidth(MainButton1Img.GetWidth()-150, GuiText::DOTTED); + MainButton1Txt.SetMaxWidth(MainButton1Img.GetWidth()-150, DOTTED); MainButton1Txt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton1Txt.SetPosition(148, -12); GuiText MainButton1DescTxt(MainButtonText, 18, (GXColor) {0, 0, 0, 255}); - MainButton1DescTxt.SetMaxWidth(MainButton1Img.GetWidth()-150, GuiText::DOTTED); + MainButton1DescTxt.SetMaxWidth(MainButton1Img.GetWidth()-150, DOTTED); MainButton1DescTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton1DescTxt.SetPosition(148, 15); GuiText MainButton1DescOverTxt(MainButtonText, 18, (GXColor) { 0, 0, 0, 255}); - MainButton1DescOverTxt.SetMaxWidth(MainButton1Img.GetWidth()-150, GuiText::SCROLL); + MainButton1DescOverTxt.SetMaxWidth(MainButton1Img.GetWidth()-150, SCROLL_HORIZONTAL); MainButton1DescOverTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton1DescOverTxt.SetPosition(148, 15); GuiButton MainButton1(MainButton1Img.GetWidth(), MainButton1Img.GetHeight()); @@ -220,15 +220,15 @@ int MenuHomebrewBrowse() { GuiText MainButton2Txt(MainButtonText, 18, (GXColor) {0, 0, 0, 255 }); MainButton2Txt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton2Txt.SetPosition(148, -12); - MainButton2Txt.SetMaxWidth(MainButton2Img.GetWidth()-150, GuiText::DOTTED); + MainButton2Txt.SetMaxWidth(MainButton2Img.GetWidth()-150, DOTTED); GuiText MainButton2DescTxt(MainButtonText, 18, (GXColor) { 0, 0, 0, 255}); MainButton2DescTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton2DescTxt.SetPosition(148, 15); - MainButton2DescTxt.SetMaxWidth(MainButton2Img.GetWidth()-150, GuiText::DOTTED); + MainButton2DescTxt.SetMaxWidth(MainButton2Img.GetWidth()-150, DOTTED); GuiText MainButton2DescOverTxt(MainButtonText, 18, (GXColor) {0, 0, 0, 255}); MainButton2DescOverTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton2DescOverTxt.SetPosition(148, 15); - MainButton2DescOverTxt.SetMaxWidth(MainButton2Img.GetWidth()-150, GuiText::SCROLL); + MainButton2DescOverTxt.SetMaxWidth(MainButton2Img.GetWidth()-150, SCROLL_HORIZONTAL); GuiButton MainButton2(MainButton2Img.GetWidth(), MainButton2Img.GetHeight()); MainButton2.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); MainButton2.SetPosition(0, 160); @@ -247,15 +247,15 @@ int MenuHomebrewBrowse() { GuiText MainButton3Txt(MainButtonText, 18, (GXColor) {0, 0, 0, 255}); MainButton3Txt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton3Txt.SetPosition(148, -12); - MainButton3Txt.SetMaxWidth(MainButton3Img.GetWidth()-150, GuiText::DOTTED); + MainButton3Txt.SetMaxWidth(MainButton3Img.GetWidth()-150, DOTTED); GuiText MainButton3DescTxt(MainButtonText, 18, (GXColor) { 0, 0, 0, 255}); MainButton3DescTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton3DescTxt.SetPosition(148, 15); - MainButton3DescTxt.SetMaxWidth(MainButton3Img.GetWidth()-150, GuiText::DOTTED); + MainButton3DescTxt.SetMaxWidth(MainButton3Img.GetWidth()-150, DOTTED); GuiText MainButton3DescOverTxt(MainButtonText, 18, (GXColor) {0, 0, 0, 255 }); MainButton3DescOverTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton3DescOverTxt.SetPosition(148, 15); - MainButton3DescOverTxt.SetMaxWidth(MainButton3Img.GetWidth()-150, GuiText::SCROLL); + MainButton3DescOverTxt.SetMaxWidth(MainButton3Img.GetWidth()-150, SCROLL_HORIZONTAL); GuiButton MainButton3(MainButton3Img.GetWidth(), MainButton3Img.GetHeight()); MainButton3.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); MainButton3.SetPosition(0, 230); @@ -274,15 +274,15 @@ int MenuHomebrewBrowse() { GuiText MainButton4Txt(MainButtonText, 18, (GXColor) {0, 0, 0, 255} ); MainButton4Txt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton4Txt.SetPosition(148, -12); - MainButton4Txt.SetMaxWidth(MainButton4Img.GetWidth()-150, GuiText::DOTTED); + MainButton4Txt.SetMaxWidth(MainButton4Img.GetWidth()-150, DOTTED); GuiText MainButton4DescTxt(MainButtonText, 18, (GXColor) {0, 0, 0, 255}); MainButton4DescTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton4DescTxt.SetPosition(148, 15); - MainButton4DescTxt.SetMaxWidth(MainButton4Img.GetWidth()-150, GuiText::DOTTED); + MainButton4DescTxt.SetMaxWidth(MainButton4Img.GetWidth()-150, DOTTED); GuiText MainButton4DescOverTxt(MainButtonText, 18, (GXColor) { 0, 0, 0, 255}); MainButton4DescOverTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); MainButton4DescOverTxt.SetPosition(148, 15); - MainButton4DescOverTxt.SetMaxWidth(MainButton4Img.GetWidth()-150, GuiText::SCROLL); + MainButton4DescOverTxt.SetMaxWidth(MainButton4Img.GetWidth()-150, SCROLL_HORIZONTAL); GuiButton MainButton4(MainButton4Img.GetWidth(), MainButton4Img.GetHeight()); MainButton4.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); MainButton4.SetPosition(0, 300); diff --git a/source/libwiigui/Text.cpp b/source/libwiigui/Text.cpp new file mode 100644 index 00000000..246a661a --- /dev/null +++ b/source/libwiigui/Text.cpp @@ -0,0 +1,350 @@ +#include "Text.hpp" + +Text::Text(const char * t, int s, GXColor c) + : GuiText(t, s, c) +{ + maxWidth = 400; + linestodraw = 9; + curLineStart = 0; + FirstLineOffset = 0; + wText = NULL; + + if(!text) + return; + + wText = new (std::nothrow) wString(text); + if(!wText) + { + return; + } + + if(wText->size() == 0) + { + wText->push_back(L' '); + wText->push_back(0); + } + + textWidth = (font ? font : fontSystem)->getWidth(wText->data(), currentSize); + delete [] text; + text = NULL; + + SetMaxWidth(maxWidth); +} + +Text::Text(const wchar_t * t, int s, GXColor c) + : GuiText((wchar_t *) NULL, s, c) +{ + maxWidth = 400; + linestodraw = 9; + curLineStart = 0; + FirstLineOffset = 0; + wText = NULL; + + if(!t) + return; + + wText = new (std::nothrow) wString(t); + if(!wText) + { + return; + } + + if(wText->size() == 0) + { + wText->push_back(L' '); + wText->push_back(0); + } + + textWidth = (font ? font : fontSystem)->getWidth(wText->data(), currentSize); + + SetMaxWidth(maxWidth); +} + +Text::~Text() +{ + if(wText) + delete wText; + wText = NULL; + + TextLines.clear(); + ClearDynamicText(); +} + +void Text::SetText(const char * t) +{ + wchar_t * tmp = charToWideChar(t); + if(!tmp) + return; + + if(wText) + delete wText; + + wText = new (std::nothrow) wString(tmp); + if(!wText) + { + return; + } + + if(wText->size() == 0) + { + wText->push_back(L' '); + wText->push_back(0); + } + + textWidth = (font ? font : fontSystem)->getWidth(wText->data(), currentSize); + + delete [] tmp; + + ClearDynamicText(); + CalcLineOffsets(); +} + +void Text::SetText(const wchar_t * t) +{ + if(!t) + return; + + if(wText) + delete wText; + + wText = new wString(t); + textWidth = (font ? font : fontSystem)->getWidth(wText->data(), currentSize); + CalcLineOffsets(); +} + +void Text::SetMaxWidth(int w) +{ + maxWidth = w; + curLineStart = 0; + Refresh(); +} + +void Text::SetTextLine(int line) +{ + if(line < 0) + line = 0; + else if(line > (int) TextLines.size()-1) + line = TextLines.size()-1; + + curLineStart = line; + + FillRows(); + + while((int) textDyn.size() < linestodraw && curLineStart > 0) + { + PreviousLine(); + } +} + +void Text::SetTextPos(int pos) +{ + if(!wText) + return; + + int diff = 10000; + + for(u32 i = 0; i < TextLines.size(); i++) + { + int curDiff = abs(TextLines[i].LineOffset - pos); + if(curDiff < diff) + { + diff = curDiff; + curLineStart = i; + } + } + + FillRows(); + + while((int) textDyn.size() < linestodraw && curLineStart > 0) + { + PreviousLine(); + } +} + +const wchar_t * Text::GetText() +{ + return wText->c_str(); +} + +std::string Text::GetUTF8String(void) const +{ + return wText->toUTF8(); +} + +int Text::GetLineOffset(int ind) +{ + if(TextLines.size() == 0) + return 0; + + if(ind < 0) + return TextLines[0].LineOffset; + + if(ind >= (int) TextLines.size()-1) + return TextLines[TextLines.size()-1].LineOffset; + + return TextLines[ind].LineOffset; +} + +const wchar_t * Text::GetTextLine(int ind) +{ + if(filling || textDyn.size() == 0) + return NULL; + + if(ind < 0) + return textDyn[0]; + + if(ind >= (int) textDyn.size()) + return textDyn[textDyn.size()-1]; + + return textDyn[ind]; +} + +void Text::Refresh() +{ + CalcLineOffsets(); + FillRows(); +} + +void Text::NextLine() +{ + if(!wText || (curLineStart+1 > ((int) TextLines.size()-linestodraw))) + return; + + ++curLineStart; + + FillRows(); +} + +void Text::PreviousLine() +{ + if(!wText || curLineStart-1 < 0) + return; + + --curLineStart; + + FillRows(); +} + +void Text::FillRows() +{ + if(!wText) + return; + + filling = true; + + ClearDynamicText(); + + for(int i = 0; i < linestodraw && i < (int) TextLines.size(); i++) + { + if(i >= (int) textDyn.size()) + { + textDyn.resize(i+1); + textDyn[i] = new wchar_t[maxWidth]; + } + int offset = TextLines[curLineStart+i].LineOffset; + int count = TextLines[curLineStart+i].CharCount+1; + + for(int n = 0; n < count && offset+n < (int) wText->size(); n++) + textDyn[i][n] = wText->at(offset+n); + + textDyn[i][count] = 0; + } + + filling = false; + + return; +} + +void Text::CalcLineOffsets() +{ + if(!wText) + return; + + TextLines.clear(); + + TextLine TmpLine; + TmpLine.CharCount = 0; + TmpLine.LineOffset = 0; + TmpLine.width = 0; + + const wchar_t * origTxt = wText->c_str(); + int ch = 0; + int lastSpace = -1; + int lastSpaceIndex = -1; + int currWidth = 0; + int i = 0; + + while(origTxt[ch]) + { + currWidth += fontSystem->getCharWidth(origTxt[ch], currentSize, ch > 0 ? origTxt[ch-1] : 0x0000); + + if(currWidth >= maxWidth) + { + if(lastSpace > 0) + { + ch = lastSpace; + } + TmpLine.CharCount = ch-TmpLine.LineOffset; + TmpLine.width = currWidth; + TextLines.push_back(TmpLine); + currWidth = 0; + lastSpace = -1; + i = -1; + TmpLine.LineOffset = ch+1; + } + else if(origTxt[ch] == '\n') + { + TmpLine.CharCount = ch-TmpLine.LineOffset; + TmpLine.width = currWidth; + TextLines.push_back(TmpLine); + currWidth = 0; + lastSpace = -1; + i = -1; + TmpLine.LineOffset = ch+1; + } + else if(origTxt[ch] == ' ') + { + lastSpace = ch; + lastSpaceIndex = i; + } + + ch++; + i++; + } + + TmpLine.CharCount = ch-TmpLine.LineOffset; + TmpLine.width = currWidth; + + if(TmpLine.CharCount > 0) + TextLines.push_back(TmpLine); +} + +void Text::Draw() +{ + if(textDyn.size() == 0) + return; + + if(!this->IsVisible()) + return; + + GXColor c = color; + c.a = this->GetAlpha(); + + int newSize = size*GetScale(); + + if(newSize != currentSize) + { + currentSize = newSize; + + if(wText) + textWidth = (font ? font : fontSystem)->getWidth(wText->data(), currentSize); + } + + u16 lineheight = newSize + 6; + + for(u32 i = 0; i < textDyn.size(); i++) + { + if(!filling) + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop()+i*lineheight, 0, textDyn[i], currentSize, c, style, 0, maxWidth); + } +} diff --git a/source/libwiigui/Text.hpp b/source/libwiigui/Text.hpp new file mode 100644 index 00000000..0db64dcb --- /dev/null +++ b/source/libwiigui/Text.hpp @@ -0,0 +1,71 @@ +#ifndef _TEXT_HPP_ +#define _TEXT_HPP_ + +#include "libwiigui/gui.h" +#include "wstring.hpp" + +typedef struct +{ + int LineOffset; + int CharCount; + int width; +} TextLine; + +class Text : public GuiText +{ + public: + //!Constructor + //!\param t Text + //!\param s Font size + //!\param c Font color + Text(const char * t, int s, GXColor c); + Text(const wchar_t * t, int s, GXColor c); + ~Text(); + //!Sets the text of the GuiText element + //!\param t Text + void SetText(const char * t); + void SetText(const wchar_t * t); + //!Set the max texwidth + void SetMaxWidth(int width); + //!Go to next line + void NextLine(); + //!Go to previous line + void PreviousLine(); + //!Refresh the rows to draw + void Refresh(); + //!Set the text line + void SetTextLine(int line); + //!Set to the char pos in text + void SetTextPos(int pos); + //!Refresh the rows to draw + int GetCurrPos() { return curLineStart; }; + //!Get the count of loaded lines + int GetLinesCount() { return textDyn.size(); }; + //!Get the total count of lines + int GetTotalLinesCount() { return TextLines.size(); }; + //!Get the original full Text + const wchar_t * GetText(); + //!Get the original full Text as wString + wString * GetwString() { return wText; }; + //!Get the original Text as a UTF-8 text + //!memory is allocated in this + //!which needs to be deleted later + std::string GetUTF8String() const; + //!Get a Textline + const wchar_t * GetTextLine(int ind); + //!Get the offset in the text of a drawn Line + int GetLineOffset(int ind); + //!Constantly called to draw the text + void Draw(); + protected: + void CalcLineOffsets(); + void FillRows(); + + wString * wText; + std::vector TextLines; + int curLineStart; + int FirstLineOffset; + bool filling; +}; + +#endif diff --git a/source/libwiigui/gui.h b/source/libwiigui/gui.h index 83b62db9..289dab6a 100644 --- a/source/libwiigui/gui.h +++ b/source/libwiigui/gui.h @@ -91,6 +91,14 @@ enum TRIGGER_BUTTON_ONLY_IN_FOCUS }; +enum +{ + WRAP, + DOTTED, + SCROLL_HORIZONTAL, + SCROLL_NONE +}; + typedef struct _paddata { u16 btns_d; u16 btns_u; @@ -144,7 +152,7 @@ class GuiSound bool Load(const char *p); //!Destructor ~GuiSound(); - + //!Start sound playback void Play(); //!Stop sound playback @@ -430,7 +438,7 @@ class GuiElement void Lock(); void Unlock(); // static mutex_t mutex; - static mutex_t _lock_mutex; + static mutex_t _lock_mutex; lwp_t _lock_thread; u16 _lock_count; lwpq_t _lock_queue; @@ -700,7 +708,6 @@ class GuiImage : public GuiElement short widescreen; //added bool parentangle; }; - //!Display, manage, and manipulate text in the GUI class GuiText : public GuiElement { @@ -711,6 +718,11 @@ class GuiText : public GuiElement //!\param c Font color GuiText(const char * t, int s, GXColor c); //!\overload + //!\param t Text + //!\param s Font size + //!\param c Font color + GuiText(const wchar_t * t, int s, GXColor c); + //!\overload //!\Assumes SetPresets() has been called to setup preferred text attributes //!\param t Text GuiText(const char * t); @@ -718,9 +730,9 @@ class GuiText : public GuiElement ~GuiText(); //!Sets the text of the GuiText element //!\param t Text - void SetText(const char * t); - void SetTextf(const char *format, ...) __attribute__((format(printf,2,3))); - void SetText(const wchar_t * t); + virtual void SetText(const char * t); + virtual void SetText(const wchar_t * t); + virtual void SetTextf(const char *format, ...) __attribute__((format(printf,2,3))); //!Sets up preset values to be used by GuiText(t) //!Useful when printing multiple text elements, all with the same attributes set //!\param sz Font size @@ -730,7 +742,7 @@ class GuiText : public GuiElement //!\param s Font style //!\param h Text alignment (horizontal) //!\param v Text alignment (vertical) - static void SetPresets(int sz, GXColor c, int w, int wrap, u16 s, int h, int v); + static void SetPresets(int sz, GXColor c, int w, u16 s, int h, int v); //!Sets the font size //!\param s Font size void SetFontSize(int s); @@ -738,60 +750,72 @@ class GuiText : public GuiElement //!If the text exceeds this, it is wrapped to the next line //!\param w Maximum width //!\param m WrapMode - enum { - WRAP, - DOTTED, - SCROLL, - MARQUEE - }; - void SetMaxWidth(int w, short m=GuiText::WRAP); + void SetMaxWidth(int w = 0, int m = WRAP); //!Sets the font color //!\param c Font color void SetColor(GXColor c); //!Sets the FreeTypeGX style attributes //!\param s Style attributes //!\param m Style-Mask attributes - void SetStyle(u16 s, u16 m=0xffff); + void SetStyle(u16 s); //!Sets the text alignment //!\param hor Horizontal alignment (ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTRE) //!\param vert Vertical alignment (ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE) void SetAlignment(int hor, int vert); + //!Set PassChar + void SetPassChar(wchar_t p); //!Sets the font //!\param f Font void SetFont(FreeTypeGX *f); - //!Sets a password character - //!\param p char - void SetPassChar(wchar_t p); + //!Get the original text as char + virtual const wchar_t * GetText(); //!Get the Horizontal Size of Text int GetTextWidth(); - // not NULL set horizontal scale to 0.75 //added - void SetWidescreen(bool w); - void SetNumLines(int n);//! these two are used to set the first line and numLine - void SetFirstLine(int n); - int GetNumLines();//! these return the line variables for this text - int GetFirstLine(); - int GetLineHeight(int n);//! returns the height of the #n of lines including spacing if wrap mode is on - int GetTotalLines(); + int GetTextWidth(int ind); + //!Get the max textwidth + int GetTextMaxWidth(); + //!Gets the total line number + virtual int GetLinesCount() { return 1; }; + //!Get fontsize + int GetFontSize() { return size; }; + //!Set max lines to draw + void SetLinesToDraw(int l); + void SetWidescreen(bool b) { widescreen = b; }; + //!Get current Textline (for position calculation) + const wchar_t * GetDynText(int ind = 0); + virtual const wchar_t * GetTextLine(int ind) { return GetDynText(ind); }; + //!Change the font + //!\param font bufferblock + //!\param font filesize + bool SetFont(const u8 *font, const u32 filesize); //!Constantly called to draw the text void Draw(); protected: - wchar_t* text; //!< Unicode text value + //!Clear the dynamic text + void ClearDynamicText(); + //!Create a dynamic dotted text if the text is too long + void MakeDottedText(); + //!Scroll the text once + void ScrollText(); + //!Wrap the text to several lines + void WrapText(); + + wchar_t *text; + std::vector textDyn; + int wrapMode; //!< Wrapping toggle + int textScrollPos; //!< Current starting index of text string for scrolling + int textScrollInitialDelay; //!< Delay to wait before starting to scroll + int textScrollDelay; //!< Scrolling speed int size; //!< Font size int maxWidth; //!< Maximum width of the generated text object (for text wrapping) - short wrapMode; - short scrollPos1; - short scrollPos2; - short scrollOffset; - u32 scrollDelay; u16 style; //!< FreeTypeGX style attributes GXColor color; //!< Font color FreeTypeGX *font; - short widescreen; //added - //!these are default until the text is drawn - int firstLine; //!these are the first line and the number of lines drawn when the text is wrapped - int numLines;//! default is -1 and it means that all lines are drawn - int totalLines; //!this is the total # of lines when in wrap mode - wchar_t passChar; //!this is the password character + int textWidth; + int currentSize; + int linestodraw; + wchar_t passChar; + bool widescreen; }; //!Display, manage, and manipulate tooltips in the GUI. diff --git a/source/libwiigui/gui_customoptionbrowser.cpp b/source/libwiigui/gui_customoptionbrowser.cpp index 5d9f0111..50f478ff 100644 --- a/source/libwiigui/gui_customoptionbrowser.cpp +++ b/source/libwiigui/gui_customoptionbrowser.cpp @@ -241,14 +241,14 @@ GuiCustomOptionBrowser::GuiCustomOptionBrowser(int w, int h, customOptionList * optionTxt[i] = new GuiText(options->GetName(i), 20, THEME.settingstext); optionTxt[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); optionTxt[i]->SetPosition(24,0); - optionTxt[i]->SetMaxWidth(bgOptionsImg->GetWidth() - (coL2+24), GuiText::DOTTED); + optionTxt[i]->SetMaxWidth(bgOptionsImg->GetWidth() - (coL2+24), DOTTED); optionBg[i] = new GuiImage(bgOptionsEntry); - optionVal[i] = new GuiText(NULL, 20, THEME.settingstext); + optionVal[i] = new GuiText((char *) NULL, 20, THEME.settingstext); optionVal[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); - optionValOver[i] = new GuiText(NULL, 20, THEME.settingstext); + optionValOver[i] = new GuiText((char *) NULL, 20, THEME.settingstext); optionValOver[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); optionBtn[i] = new GuiButton(width-28,GAMESELECTSIZE); @@ -479,10 +479,10 @@ void GuiCustomOptionBrowser::UpdateListEntries() if(optionBtn[i]->GetState() != STATE_DISABLED) { optionVal[i]->SetPosition(coL2,0); - optionVal[i]->SetMaxWidth(bgOptionsImg->GetWidth() - (coL2+24), GuiText::DOTTED); + optionVal[i]->SetMaxWidth(bgOptionsImg->GetWidth() - (coL2+24), DOTTED); optionValOver[i]->SetPosition(coL2,0); - optionValOver[i]->SetMaxWidth(bgOptionsImg->GetWidth() - (coL2+24), GuiText::SCROLL); + optionValOver[i]->SetMaxWidth(bgOptionsImg->GetWidth() - (coL2+24), SCROLL_HORIZONTAL); } } } diff --git a/source/libwiigui/gui_filebrowser.cpp b/source/libwiigui/gui_filebrowser.cpp index 389c8ee0..42a6595f 100644 --- a/source/libwiigui/gui_filebrowser.cpp +++ b/source/libwiigui/gui_filebrowser.cpp @@ -108,15 +108,15 @@ GuiFileBrowser::GuiFileBrowser(int w, int h) for(int i=0; iSetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); fileListText[i]->SetPosition(5,0); - fileListText[i]->SetMaxWidth(bgFileSelectionImg->GetWidth() - (arrowDownImg->GetWidth()+20), GuiText::DOTTED); + fileListText[i]->SetMaxWidth(bgFileSelectionImg->GetWidth() - (arrowDownImg->GetWidth()+20), DOTTED); - fileListTextOver[i] = new GuiText(NULL,20, (GXColor){0, 0, 0, 0xff}); + fileListTextOver[i] = new GuiText((char *) NULL,20, (GXColor){0, 0, 0, 0xff}); fileListTextOver[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); fileListTextOver[i]->SetPosition(5,0); - fileListTextOver[i]->SetMaxWidth(bgFileSelectionImg->GetWidth() - (arrowDownImg->GetWidth()+20), GuiText::SCROLL); + fileListTextOver[i]->SetMaxWidth(bgFileSelectionImg->GetWidth() - (arrowDownImg->GetWidth()+20), SCROLL_HORIZONTAL); fileListBg[i] = new GuiImage(bgFileSelectionEntry); //fileListArchives[i] = new GuiImage(fileArchives); diff --git a/source/libwiigui/gui_gamebrowser.cpp b/source/libwiigui/gui_gamebrowser.cpp index c99c04bb..62ac1304 100644 --- a/source/libwiigui/gui_gamebrowser.cpp +++ b/source/libwiigui/gui_gamebrowser.cpp @@ -132,13 +132,13 @@ GuiGameBrowser::GuiGameBrowser(int w, int h, struct discHdr * l, int gameCnt, co gameTxt[i] = new GuiText(get_title(&gameList[i]), 20, THEME.gametext); gameTxt[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); gameTxt[i]->SetPosition(24,0); - gameTxt[i]->SetMaxWidth(maxTextWidth, GuiText::DOTTED); + gameTxt[i]->SetMaxWidth(maxTextWidth, DOTTED); gameTxtOver[i] = new GuiText(get_title(&gameList[i]), 20, THEME.gametext); gameTxtOver[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); gameTxtOver[i]->SetPosition(24,0); - gameTxtOver[i]->SetMaxWidth(maxTextWidth, GuiText::SCROLL); + gameTxtOver[i]->SetMaxWidth(maxTextWidth, SCROLL_HORIZONTAL); gameBg[i] = new GuiImage(bgGamesEntry); @@ -344,11 +344,11 @@ void GuiGameBrowser::UpdateListEntries() if (Settings.marknewtitles) { bool isNew = NewTitles::Instance()->IsNew(gameList[next].id); if (isNew) { - gameTxt[i]->SetMaxWidth(maxTextWidth - (newGames->GetWidth() + 1), GuiText::DOTTED); - gameTxtOver[i]->SetMaxWidth(maxTextWidth - (newGames->GetWidth() + 1), GuiText::SCROLL); + gameTxt[i]->SetMaxWidth(maxTextWidth - (newGames->GetWidth() + 1), DOTTED); + gameTxtOver[i]->SetMaxWidth(maxTextWidth - (newGames->GetWidth() + 1), SCROLL_HORIZONTAL); } else { - gameTxt[i]->SetMaxWidth(maxTextWidth, GuiText::DOTTED); - gameTxtOver[i]->SetMaxWidth(maxTextWidth, GuiText::SCROLL); + gameTxt[i]->SetMaxWidth(maxTextWidth, DOTTED); + gameTxtOver[i]->SetMaxWidth(maxTextWidth, SCROLL_HORIZONTAL); } newImg[i]->SetVisible(isNew); } diff --git a/source/libwiigui/gui_gamecarousel.cpp b/source/libwiigui/gui_gamecarousel.cpp index c32c6107..4a3ac43b 100644 --- a/source/libwiigui/gui_gamecarousel.cpp +++ b/source/libwiigui/gui_gamecarousel.cpp @@ -111,7 +111,7 @@ noCover(nocover_png) gamename->SetParent(this); gamename->SetAlignment(ALIGN_CENTRE, ALIGN_TOP); gamename->SetPosition(0, 330); - gamename->SetMaxWidth(280, GuiText::DOTTED); + gamename->SetMaxWidth(280, DOTTED); gameIndex = new int[pagesize]; game = new GuiButton * [pagesize]; diff --git a/source/libwiigui/gui_optionbrowser.cpp b/source/libwiigui/gui_optionbrowser.cpp index 4775c7fc..cfb02230 100644 --- a/source/libwiigui/gui_optionbrowser.cpp +++ b/source/libwiigui/gui_optionbrowser.cpp @@ -107,13 +107,13 @@ GuiOptionBrowser::GuiOptionBrowser(int w, int h, OptionList * l, const u8 *image // optionBg = new GuiImage(bgOptionsEntry); for(int i=0; iSetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); optionTxt[i]->SetPosition(24,0); optionBg[i] = new GuiImage(bgOptionsEntry); - optionVal[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff}); + optionVal[i] = new GuiText((char *) NULL, 20, (GXColor){0, 0, 0, 0xff}); optionVal[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); optionVal[i]->SetPosition(250,0); @@ -232,7 +232,7 @@ GuiOptionBrowser::GuiOptionBrowser(int w, int h, OptionList * l, const char *the optionBg[i] = new GuiImage(bgOptionsEntry); - optionVal[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff}); + optionVal[i] = new GuiText((char *) NULL, 20, (GXColor){0, 0, 0, 0xff}); optionVal[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); optionVal[i]->SetPosition(250,0); diff --git a/source/libwiigui/gui_searchbar.cpp b/source/libwiigui/gui_searchbar.cpp index 12d0007a..8a7420e6 100644 --- a/source/libwiigui/gui_searchbar.cpp +++ b/source/libwiigui/gui_searchbar.cpp @@ -16,7 +16,7 @@ public: wchar(*Char), image(keyImageData), imageOver(keyOverImageData), - text(NULL, 20, (GXColor){0, 0, 0, 0xff}), + text((char *) NULL, 20, (GXColor){0, 0, 0, 0xff}), button(&image, &imageOver, ALIGN_LEFT, ALIGN_TOP, x, y, trig, sndOver, sndClick, 1) { text.SetText(Char); @@ -35,7 +35,7 @@ private: GuiSearchBar::GuiSearchBar(const wchar_t *SearchChars) : inSide(0), -text(NULL, 22, (GXColor) {0, 0, 0, 255}), +text((char *) NULL, 22, (GXColor) {0, 0, 0, 255}), buttons(0), keyImageData(keyboard_key_png), keyOverImageData(keyboard_key_over_png), @@ -70,7 +70,7 @@ sndClick(button_click_pcm, button_click_pcm_size, Settings.sfxvolume) text.SetPosition(10, 15); text.SetAlignment(ALIGN_LEFT, ALIGN_TOP); text.SetWidescreen(CFG.widescreen); - text.SetMaxWidth(width-(10+2*42+10), GuiText::SCROLL); + text.SetMaxWidth(width-(10+2*42+10), SCROLL_HORIZONTAL); this->Append(&text); snprintf(imgPath, sizeof(imgPath), "%skeyboard_backspace_over.png", CFG.theme_path); diff --git a/source/libwiigui/gui_text.cpp b/source/libwiigui/gui_text.cpp index b3fa8e92..4ddbeaa5 100644 --- a/source/libwiigui/gui_text.cpp +++ b/source/libwiigui/gui_text.cpp @@ -9,42 +9,84 @@ ***************************************************************************/ #include "gui.h" +#include "wstring.hpp" -static int presetSize = 0; -static GXColor presetColor = (GXColor){255, 255, 255, 255}; +#define MAX_LINES_TO_DRAW 9 + +static int presetSize = 18; static int presetMaxWidth = 0; -static int presetWrapMode = GuiText::WRAP; -static u16 presetStyle = FTGX_NULL; static int presetAlignmentHor = 0; static int presetAlignmentVert = 0; +static u16 presetStyle = 0; +static GXColor presetColor = (GXColor){255, 255, 255, 255}; + +#define TEXT_SCROLL_DELAY 5 +#define TEXT_SCROLL_INITIAL_DELAY 8 /** * Constructor for the GuiText class. */ + GuiText::GuiText(const char * t, int s, GXColor c) { text = NULL; size = s; + currentSize = size; color = c; alpha = c.a; style = FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE; maxWidth = 0; - wrapMode = GuiText::WRAP; - scrollPos1 = 0; - scrollPos2 = 0; - scrollDelay = 0; - font = NULL; - widescreen = 0; //added - firstLine = 1; - numLines = -1; - totalLines = 1; + wrapMode = 0; passChar = 0; + font = NULL; + linestodraw = MAX_LINES_TO_DRAW; + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; alignmentHor = ALIGN_CENTRE; alignmentVert = ALIGN_MIDDLE; if(t) - text = FreeTypeGX::charToWideChar((char *)t); + { + text = charToWideChar(t); + if(!text) + return; + + textWidth = fontSystem->getWidth(text, currentSize); + } +} + +GuiText::GuiText(const wchar_t * t, int s, GXColor c) +{ + text = NULL; + size = s; + currentSize = size; + color = c; + alpha = c.a; + style = FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE; + maxWidth = 0; + wrapMode = 0; + passChar = 0; + font = NULL; + linestodraw = MAX_LINES_TO_DRAW; + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; + + alignmentHor = ALIGN_CENTRE; + alignmentVert = ALIGN_MIDDLE; + + if(t) + { + text = new (std::nothrow) wchar_t[wcslen(t)+1]; + if(!text) + return; + + wcscpy(text, t); + + textWidth = fontSystem->getWidth(text, currentSize); + } } /** @@ -54,175 +96,197 @@ GuiText::GuiText(const char * t) { text = NULL; size = presetSize; + currentSize = size; color = presetColor; alpha = presetColor.a; style = presetStyle; maxWidth = presetMaxWidth; - wrapMode = presetWrapMode; - scrollPos1 = 0; - scrollPos2 = 0; - scrollDelay = 0; + wrapMode = 0; + passChar = 0; font = NULL; - widescreen = 0; //added - firstLine = 1; - numLines = -1; - totalLines = 1; + linestodraw = MAX_LINES_TO_DRAW; + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; alignmentHor = presetAlignmentHor; alignmentVert = presetAlignmentVert; if(t) - text = FreeTypeGX::charToWideChar((char *)t); + { + text = charToWideChar(t); + if(!text) + return; + + textWidth = fontSystem->getWidth(text, currentSize); + } } + /** * Destructor for the GuiText class. */ GuiText::~GuiText() { - if(text) - { - delete [] text; - text = NULL; - } -} - -void GuiText::SetNumLines(int n) -{ - numLines = n; -} - -void GuiText::SetFirstLine(int n) -{ - firstLine = n; -} - -int GuiText::GetNumLines() -{ - return numLines; -} - -int GuiText::GetFirstLine() -{ - return firstLine; -} - -int GuiText::GetTotalLines() -{ - return totalLines; -} - -int GuiText::GetLineHeight(int n) -{ - int newSize = size*this->GetScale(); - int lineheight = newSize + 6; - - if (numLines <0) - return totalLines*lineheight+newSize; - - else return numLines*lineheight+newSize; -} - - -void GuiText::SetText(const char * t) -{ - LOCK(this); if(text) delete [] text; text = NULL; - if(t) { - text = FreeTypeGX::charToWideChar((char *)t); - - if (passChar != 0) { - for (u8 i = 0; i < wcslen(text); i++) { - text[i] = passChar; - } - } - } - scrollPos2 = 0; - scrollDelay = 0; + if(font) + { + delete font; + font = NULL; + } + + ClearDynamicText(); } + +void GuiText::SetText(const char * t) +{ + LOCK(this); + + if(text) + delete [] text; + text = NULL; + + ClearDynamicText(); + + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + + if(t) + { + text = charToWideChar(t); + if(!text) + return; + + if (passChar != 0) + { + for (u8 i = 0; i < wcslen(text); i++) + text[i] = passChar; + } + + textWidth = fontSystem->getWidth(text, currentSize); + } +} + void GuiText::SetTextf(const char *format, ...) { + if(!format) + SetText((char *) NULL); + char *tmp=0; va_list va; va_start(va, format); if((vasprintf(&tmp, format, va)>=0) && tmp) { - this->SetText(tmp); - free(tmp); + SetText(tmp); } va_end(va); + + if(tmp) + free(tmp); } + + void GuiText::SetText(const wchar_t * t) { - LOCK(this); + LOCK(this); + if(text) delete [] text; - text = NULL; + text = NULL; + + ClearDynamicText(); + + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; if(t) { - int len = wcslen(t); - text = new wchar_t[len+1]; - if(text) { - wcscpy(text, t); - } - - if (passChar != 0) { - for (u8 i = 0; i < wcslen(text); i++) { + text = new (std::nothrow) wchar_t[wcslen(t)+1]; + if(!text) + return; + + wcscpy(text, t); + + if (passChar != 0) + { + for (u8 i = 0; i < wcslen(text); i++) text[i] = passChar; - } } + + textWidth = fontSystem->getWidth(text, currentSize); } - scrollPos2 = 0; - scrollDelay = 0; } +void GuiText::ClearDynamicText() +{ + for(u32 i = 0; i < textDyn.size(); i++) + { + if(textDyn[i]) + delete [] textDyn[i]; + } + textDyn.clear(); +} -void GuiText::SetPresets(int sz, GXColor c, int w, int wrap, u16 s, int h, int v) +void GuiText::SetPresets(int sz, GXColor c, int w, u16 s, int h, int v) { presetSize = sz; presetColor = c; - presetMaxWidth = w; - presetWrapMode = wrap; presetStyle = s; + presetMaxWidth = w; presetAlignmentHor = h; presetAlignmentVert = v; } void GuiText::SetFontSize(int s) { - LOCK(this); + LOCK(this); + size = s; } -void GuiText::SetMaxWidth(int w, short m/*=GuiText::WRAP*/) +void GuiText::SetMaxWidth(int width, int w) +{ + LOCK(this); + + maxWidth = width; + wrapMode = w; + + if(w == SCROLL_HORIZONTAL) + { + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; + } + + ClearDynamicText(); +} + +void GuiText::SetPassChar(wchar_t p) { LOCK(this); - maxWidth = w; - wrapMode = m; + passChar = p; } void GuiText::SetColor(GXColor c) { - LOCK(this); + LOCK(this); color = c; alpha = c.a; } -void GuiText::SetStyle(u16 s, u16 m/*=0xffff*/) +void GuiText::SetStyle(u16 s) { - LOCK(this); - style &= ~m; - style |= s & m; + LOCK(this); + style = s; } void GuiText::SetAlignment(int hor, int vert) { - LOCK(this); - style = FTGX_NULL; + LOCK(this); + style = 0; switch(hor) { @@ -252,291 +316,285 @@ void GuiText::SetAlignment(int hor, int vert) alignmentHor = hor; alignmentVert = vert; } -/** - * Set a password character - */ -void GuiText::SetPassChar(wchar_t p) -{ - LOCK(this); - passChar = p; -} -/** - * Set the Font - */ -void GuiText::SetFont(FreeTypeGX *f) +void GuiText::SetLinesToDraw(int l) { - LOCK(this); - font = f; + linestodraw = l; } int GuiText::GetTextWidth() { - LOCK(this); if(!text) return 0; - - int newSize = size*this->GetScale(); - (font ? font : fontSystem)->changeSize(newSize, widescreen ? newSize*0.8 : 0); - return (font ? font : fontSystem)->getWidth(text); + return fontSystem->getWidth(text, currentSize); } -void GuiText::SetWidescreen(bool w) +int GuiText::GetTextWidth(int ind) { - LOCK(this); - widescreen = w; + if(ind < 0 || ind >= (int) textDyn.size()) + return this->GetTextWidth(); + + return fontSystem->getWidth(textDyn[ind], currentSize); } + +int GuiText::GetTextMaxWidth() +{ + return maxWidth; +} + +const wchar_t * GuiText::GetDynText(int ind) +{ + if(ind < 0 || ind >= (int) textDyn.size()) + return text; + + return textDyn[ind]; +} + +const wchar_t * GuiText::GetText() +{ + return text; +} + +/** + * Change font + */ +bool GuiText::SetFont(const u8 *fontbuffer, const u32 filesize) +{ + if(!fontbuffer || !filesize) + return false; + + LOCK(this); + if(font) + { + delete font; + font = NULL; + } + font = new FreeTypeGX(fontbuffer, filesize); + textWidth = font->getWidth(text, currentSize); + + return true; +} + +void GuiText::MakeDottedText() +{ + int pos = textDyn.size(); + textDyn.resize(pos+1); + + int i = 0, currentWidth = 0; + textDyn[pos] = new wchar_t[maxWidth]; + + while(text[i]) + { + currentWidth += (font ? font : fontSystem)->getCharWidth(text[i], currentSize, i > 0 ? text[i-1] : 0x0000); + if(currentWidth >= maxWidth) + { + if(i > 3) + { + textDyn[pos][i-3] = '.'; + textDyn[pos][i-2] = '.'; + textDyn[pos][i-1] = '.'; + } + break; + } + + textDyn[pos][i] = text[i]; + + i++; + } + textDyn[pos][i] = 0; +} + +void GuiText::ScrollText() +{ + if(textDyn.size() == 0) + { + int pos = textDyn.size(); + int i = 0, currentWidth = 0; + textDyn.resize(pos+1); + + textDyn[pos] = new wchar_t[maxWidth]; + + while(text[i] && currentWidth < maxWidth) + { + textDyn[pos][i] = text[i]; + + currentWidth += (font ? font : fontSystem)->getCharWidth(text[i], currentSize, i > 0 ? text[i-1] : 0x0000); + + ++i; + } + textDyn[pos][i] = 0; + + return; + } + + if(frameCount % textScrollDelay != 0) + { + return; + } + + if(textScrollInitialDelay) + { + --textScrollInitialDelay; + return; + } + + int strlen = wcslen(text); + + ++textScrollPos; + if(textScrollPos > strlen) + { + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + } + + int ch = textScrollPos; + int pos = textDyn.size()-1; + + if(textDyn[pos]) + delete [] textDyn[pos]; + + textDyn[pos] = new wchar_t[maxWidth]; + + int i = 0, currentWidth = 0; + + while(currentWidth < maxWidth) + { + if(ch > strlen-1) + { + textDyn[pos][i++] = ' '; + textDyn[pos][i++] = ' '; + textDyn[pos][i++] = ' '; + ch = 0; + } + + textDyn[pos][i] = text[ch]; + ++ch; + ++i; + + currentWidth += (font ? font : fontSystem)->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch-1] : 0x0000); + } + textDyn[pos][i] = 0; +} + +void GuiText::WrapText() +{ + if(textDyn.size() > 0) + return; + + int i = 0; + int ch = 0; + int linenum = 0; + int lastSpace = -1; + int lastSpaceIndex = -1; + int currentWidth = 0; + + while(text[ch] && linenum < linestodraw) + { + if(linenum >= (int) textDyn.size()) + { + textDyn.resize(linenum+1); + textDyn[linenum] = new wchar_t[maxWidth]; + } + + textDyn[linenum][i] = text[ch]; + textDyn[linenum][i+1] = 0; + + currentWidth += (font ? font : fontSystem)->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch-1] : 0x0000); + + if(currentWidth >= maxWidth) + { + if(lastSpace >= 0) + { + textDyn[linenum][lastSpaceIndex] = 0; // discard space, and everything after + ch = lastSpace; // go backwards to the last space + lastSpace = -1; // we have used this space + lastSpaceIndex = -1; + } + + if(linenum+1 == linestodraw && text[ch+1] != 0x0000) + { + textDyn[linenum][i-2] = '.'; + textDyn[linenum][i-1] = '.'; + textDyn[linenum][i] = '.'; + textDyn[linenum][i+1] = 0; + } + + currentWidth = 0; + ++linenum; + i = -1; + } + if(text[ch] == ' ' && i >= 0) + { + lastSpace = ch; + lastSpaceIndex = i; + } + ++ch; + ++i; + } +} + /** * Draw the text on screen */ void GuiText::Draw() { - LOCK(this); if(!text) return; - if(!this->IsVisible()) + if(!IsVisible()) return; GXColor c = color; - c.a = this->GetAlpha(); + c.a = GetAlpha(); - int newSize = size*this->GetScale(); + int newSize = size*GetScale(); - (font ? font : fontSystem)->changeSize(newSize, widescreen ? newSize*0.8 : 0); - int voffset = 0; - -// if(alignmentVert == ALIGN_MIDDLE) -// voffset = -newSize/2 + 2; - - if(maxWidth > 0 && (font ? font : fontSystem)->getWidth(text) > maxWidth) + if(newSize != currentSize) { - if(wrapMode == GuiText::WRAP) // text wrapping + currentSize = newSize; + + if(text) + textWidth = (font ? font : fontSystem)->getWidth(text, currentSize); + } + + if(maxWidth > 0 && maxWidth <= textWidth) + { + if(wrapMode == DOTTED) // text dotted { - int lineheight = newSize + 6; - int strlen = wcslen(text); - int i = 0; - int ch = 0; - int linenum = 0; - int linemax = 200; - int lastSpace = -1; - int lastSpaceIndex = -1; - wchar_t * tmptext[linemax]; - - totalLines=0; - while(ch < strlen) - { - if(i == 0) - { - if (linenum <= linemax) - { - tmptext[linenum] = new wchar_t[strlen + 1]; - } - else - { - break; - } - } - - tmptext[linenum][i] = text[ch]; - tmptext[linenum][i+1] = 0; + if(textDyn.size() == 0) + MakeDottedText(); - //if(text[ch] == ' ' || ch == strlen-1) - //{ - if((font ? font : fontSystem)->getWidth(tmptext[linenum]) >= maxWidth) - //if(fontSystem->getWidth(tmptext[linenum]) >= maxWidth) - { - if(lastSpace >= 0) - { - tmptext[linenum][lastSpaceIndex] = 0; // discard space, and everything after - ch = lastSpace; // go backwards to the last space - lastSpace = -1; // we have used this space - lastSpaceIndex = -1; - } - linenum++; - i = -1; - } - else if(ch == strlen-1) - { - linenum++; - } - //} - if(text[ch] == ' ' && i >= 0) - { - lastSpace = ch; - lastSpaceIndex = i; - } - if(text[ch] == '\n' && ch != strlen-1 && i >= 0) - { - linenum++; - i = -1; - } - ch++; - i++; - } - totalLines = linenum; - - if(alignmentVert == ALIGN_MIDDLE) - voffset = voffset - (lineheight*linenum)/2 + lineheight/2; - - if (numLines <0){ - for(i=0; i < linenum; i++) - { - (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop()+voffset+i*lineheight, tmptext[i], c, style); - delete tmptext[i]; - } - } - - //put in for txt vertical txt scrolling - else { - int j; - i=0; - for(j=firstLine-1; j < numLines+firstLine-1; j++) - { - //if (jdrawText(this->GetLeft(), this->GetTop()+voffset+i*lineheight, tmptext[j], c, style); - i++; - } - for(i=0; i < linenum; i++) - { - delete tmptext[i]; - } - } - - + if(textDyn.size() > 0) + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop(), 0, textDyn[textDyn.size()-1], currentSize, c, style); } - else if(wrapMode == GuiText::DOTTED) // text dotted + + else if(wrapMode == SCROLL_HORIZONTAL) { - wchar_t save[4]; - int strlen = wcslen(text); - int dotPos=strlen-3; - int i; - bool drawed = false; - while(dotPos > 0 && drawed == false) - { - for(i=0; i<4; i++) // save Text for "..." - { - save[i] = text[dotPos+i]; - text[dotPos+i] = (i != 3 ? _TEXT('.') : 0); - } - if(((font ? font : fontSystem)->getWidth(text)) <= maxWidth) - { - (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style); - drawed = true; - } + ScrollText(); - for(i=0; i<4; i++) // write saved Text back - text[dotPos+i] = save[i]; - dotPos--; - } - if(!drawed) - (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style); - } - else if(wrapMode == GuiText::SCROLL) // text scroller + if(textDyn.size() > 0) + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop(), 0, textDyn[textDyn.size()-1], currentSize, c, style); + } + else if(wrapMode == WRAP) { - wchar_t save; - - if(scrollPos2 == 0 || frameCount > scrollDelay+5) - { - scrollPos1 = 0; - scrollOffset = 0; - for(scrollPos2 = wcslen(text); scrollPos2 > 1; scrollPos2--) - { - save = text[scrollPos2]; // save Pos2 - text[scrollPos2] = 0; - int textWidth = (font ? font : fontSystem)->getWidth(text); - text[scrollPos2] = save; // restore Pos2 - if(textWidth <= maxWidth) - break; - } - scrollDelay = frameCount+50; // wait 50 Frames before beginning with scrolling - } - else if(scrollPos2 > 0 && frameCount >= scrollDelay) - { - - if(--scrollOffset < 0) - { - wchar_t tmp[] = { text[scrollPos1], text[scrollPos1+1], 0 }; - scrollOffset += (font ? font : fontSystem)->getWidth(tmp) - (font ? font : fontSystem)->getWidth(tmp+1); - scrollPos1++; - } - - int strlen = wcslen(text); - for(; scrollPos2 < strlen; scrollPos2++) - { - save = text[scrollPos2+1]; // save Pos2 - text[scrollPos2+1] = 0; - int textWidth = (font ? font : fontSystem)->getWidth(&text[scrollPos1]); - text[scrollPos2+1] = save; // restore Pos2 - if(textWidth+scrollOffset > maxWidth) - break; - } - if(scrollPos2 == strlen) - { - scrollPos2 = -scrollPos2; - scrollDelay = frameCount+25; // when dir-change wait 25 Frames - } - else - scrollDelay = frameCount+1; // wait 1 Frames - } - else if(frameCount >= scrollDelay) - { - scrollPos2 = -scrollPos2; - - scrollOffset++; - wchar_t tmp[] = { text[scrollPos1-1], text[scrollPos1], 0 }; - int tmpOffset = (font ? font : fontSystem)->getWidth(tmp) - (font ? font : fontSystem)->getWidth(tmp+1); - if(scrollOffset >= tmpOffset) - { - scrollOffset -= tmpOffset; - scrollPos1--; - } + int lineheight = currentSize + 6; + int voffset = 0; + if(alignmentVert == ALIGN_MIDDLE) + voffset = -(lineheight*textDyn.size())/2 + lineheight/2; - for(; scrollPos2 > scrollPos1; scrollPos2--) - { - save = text[scrollPos2]; // save Pos2 - text[scrollPos2] = 0; - int textWidth = (font ? font : fontSystem)->getWidth(&text[scrollPos1]); - text[scrollPos2] = save; // restore Pos2 - if(textWidth+scrollOffset <= maxWidth) - break; - } - if(scrollPos1 == 0) - { - scrollPos2 = -scrollPos2; - scrollDelay = frameCount+25; // when dir-change wait 25 Frames - } - else - scrollDelay = frameCount+1; // wait 10 Frames + if(textDyn.size() == 0) + WrapText(); - scrollPos2 = -scrollPos2; - } - - uint16_t drawStyle = style; - uint16_t drawX = this->GetLeft() + scrollOffset; - - if((drawStyle & FTGX_JUSTIFY_MASK) == FTGX_JUSTIFY_CENTER) - { - drawStyle = (drawStyle & ~FTGX_JUSTIFY_MASK) | FTGX_JUSTIFY_LEFT; - drawX -= maxWidth >> 1; - } - else if((drawStyle & FTGX_JUSTIFY_MASK) == FTGX_JUSTIFY_RIGHT) - { - drawStyle = (drawStyle & ~FTGX_JUSTIFY_MASK) | FTGX_JUSTIFY_LEFT; - drawX -= maxWidth; - } - - save = text[abs(scrollPos2)]; // save Pos2 - text[abs(scrollPos2)] = 0; - (font ? font : fontSystem)->drawText(drawX, this->GetTop()+voffset, &text[scrollPos1], c, drawStyle); - text[abs(scrollPos2)] = save; // restore Pos2 + for(u32 i = 0; i < textDyn.size(); i++) + { + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop()+voffset+i*lineheight, 0, textDyn[i], currentSize, c, style); + } } } else { - (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style); + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop(), 0, text, currentSize, c, style, textWidth); } this->UpdateEffects(); } diff --git a/source/main.cpp b/source/main.cpp index 9ed977a5..516aae96 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -33,6 +33,7 @@ extern "C" #include "mload/mload.h" #include "mload/mload_modules.h" #include "FreeTypeGX.h" +#include "FontSystem.h" #include "video.h" #include "audio.h" #include "menu.h" @@ -63,8 +64,6 @@ extern char headlessID[8]; #define CONSOLE_WIDTH 340 #define CONSOLE_HEIGHT 218 -FreeTypeGX *fontSystem=0; -FreeTypeGX *fontClock=0; PartList partitions; u8 dbvideo =0; @@ -125,6 +124,7 @@ int main(int argc, char *argv[]) printf("\n\tCheck for an existing cIOS"); CheckForCIOS(); + printf("\n\tcIOS = %u (Rev %u)",IOS_GetVersion(), IOS_GetRevision()); // Let's load the cIOS now if(LoadAppCIOS() < 0) @@ -134,13 +134,12 @@ int main(int argc, char *argv[]) Sys_BackToLoader(); } - printf("\n\tcIOS = %u (Rev %u)",IOS_GetVersion(), IOS_GetRevision()); - - // Init WBFS - int ret = WBFS_Init(WBFS_DEVICE_USB); - if (ret < 0) + printf("\n\tWaiting for USB: "); + if (MountWBFS() < 0) { printf("\nERROR: No WBFS drive mounted."); + sleep(5); + exit(0); } //if a ID was passed via args copy it and try to boot it after the partition is mounted @@ -159,18 +158,11 @@ int main(int argc, char *argv[]) WPAD_SetDataFormat(WPAD_CHAN_ALL,WPAD_FMT_BTNS_ACC_IR); WPAD_SetVRes(WPAD_CHAN_ALL, screenwidth, screenheight); - // load main font from file, or default to built-in font - fontSystem = new FreeTypeGX(); char *fontPath = NULL; asprintf(&fontPath, "%sfont.ttf", CFG.theme_path); - fontSystem->loadFont(fontPath, font_ttf, font_ttf_size, 0); - fontSystem->setCompatibilityMode(FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_PASSCLR | FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE); + SetupDefaultFont(fontPath); free(fontPath); - fontClock = new FreeTypeGX(); - fontClock->loadFont(NULL, clock_ttf, clock_ttf_size, 0); - fontClock->setCompatibilityMode(FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_PASSCLR | FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE); - gprintf("\n\tEnd of Main()"); InitGUIThreads(); MainMenu(MENU_CHECK); diff --git a/source/menu.cpp b/source/menu.cpp index 242b2b53..2f9b3963 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -65,7 +65,6 @@ static int ExitRequested = 0; /*** Extern variables ***/ extern struct discHdr * gameList; -extern FreeTypeGX *fontClock; extern u8 shutdown; extern u8 reset; extern s32 gameSelected, gameStart; @@ -343,7 +342,6 @@ int MainMenu(int menu) { delete GameIDTxt; delete cover; delete coverImg; - delete fontClock; delete fontSystem; ShutdownAudio(); StopGX(); diff --git a/source/menu/menu_disclist.cpp b/source/menu/menu_disclist.cpp index 1cdecf26..76283971 100644 --- a/source/menu/menu_disclist.cpp +++ b/source/menu/menu_disclist.cpp @@ -559,11 +559,11 @@ int MenuDiscList() { GuiText clockTimeBack("88:88", 40, (GXColor) {THEME.clock.r, THEME.clock.g, THEME.clock.b, THEME.clock.a/6}); clockTimeBack.SetAlignment(THEME.clock_align, ALIGN_TOP); clockTimeBack.SetPosition(THEME.clock_x, THEME.clock_y); - clockTimeBack.SetFont(fontClock); + clockTimeBack.SetFont(clock_ttf, clock_ttf_size); GuiText clockTime(theTime, 40, THEME.clock); clockTime.SetAlignment(THEME.clock_align, ALIGN_TOP); clockTime.SetPosition(THEME.clock_x, THEME.clock_y); - clockTime.SetFont(fontClock); + clockTime.SetFont(clock_ttf, clock_ttf_size); HaltGui(); GuiWindow w(screenwidth, screenheight); diff --git a/source/prompts/DiscBrowser.cpp b/source/prompts/DiscBrowser.cpp index d05efae6..8281e4eb 100644 --- a/source/prompts/DiscBrowser.cpp +++ b/source/prompts/DiscBrowser.cpp @@ -163,7 +163,7 @@ int DiscBrowse(struct discHdr * header) { GuiText titleTxt(get_title(header), 28, (GXColor) {0, 0, 0, 255}); titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); titleTxt.SetPosition(12,40); - titleTxt.SetMaxWidth(356, GuiText::SCROLL); + titleTxt.SetMaxWidth(356, SCROLL_HORIZONTAL); GuiImage settingsbackground(&settingsbg); GuiButton settingsbackgroundbtn(settingsbackground.GetWidth(), settingsbackground.GetHeight()); diff --git a/source/prompts/ProgressWindow.cpp b/source/prompts/ProgressWindow.cpp index 4733be17..47c719c6 100644 --- a/source/prompts/ProgressWindow.cpp +++ b/source/prompts/ProgressWindow.cpp @@ -175,30 +175,30 @@ static void ProgressWindow(const char *title, const char *msg1, const char *msg2 msg1Txt.SetPosition(0,120); else msg1Txt.SetPosition(0,100); - msg1Txt.SetMaxWidth(430, GuiText::DOTTED); + msg1Txt.SetMaxWidth(430, DOTTED); GuiText msg2Txt(msg2, 22, THEME.prompttext ); msg2Txt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); msg2Txt.SetPosition(0,125); - msg2Txt.SetMaxWidth(430, GuiText::DOTTED); + msg2Txt.SetMaxWidth(430, DOTTED); GuiText prsTxt("%", 22, THEME.prompttext); prsTxt.SetAlignment(ALIGN_RIGHT, ALIGN_MIDDLE); prsTxt.SetPosition(-188,40); - GuiText timeTxt(NULL, 22, THEME.prompttext); + GuiText timeTxt((char*) NULL, 22, THEME.prompttext); timeTxt.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); timeTxt.SetPosition(280,-50); - GuiText sizeTxt(NULL, 22, THEME.prompttext); + GuiText sizeTxt((char*) NULL, 22, THEME.prompttext); sizeTxt.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); sizeTxt.SetPosition(50, -50); - GuiText speedTxt(NULL, 22, THEME.prompttext); + GuiText speedTxt((char*) NULL, 22, THEME.prompttext); speedTxt.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); speedTxt.SetPosition(50, -74); - GuiText prTxt(NULL, 26, THEME.prompttext); + GuiText prTxt((char*) NULL, 26, THEME.prompttext); prTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); prTxt.SetPosition(200, 40); @@ -208,8 +208,8 @@ static void ProgressWindow(const char *title, const char *msg1, const char *msg2 progressbarEmptyImg.SetPosition(80,40); progressbarEmptyImg.SetTile(78); progressbarImg.SetPosition(80, 40); - msg1Txt.SetMaxWidth(380, GuiText::DOTTED); - msg2Txt.SetMaxWidth(380, GuiText::DOTTED); + msg1Txt.SetMaxWidth(380, DOTTED); + msg2Txt.SetMaxWidth(380, DOTTED); timeTxt.SetPosition(250,-50); timeTxt.SetFontSize(20); diff --git a/source/prompts/PromptWindows.cpp b/source/prompts/PromptWindows.cpp index 8433cde0..4d1c8c69 100644 --- a/source/prompts/PromptWindows.cpp +++ b/source/prompts/PromptWindows.cpp @@ -15,6 +15,7 @@ #include "language/gettext.h" #include "libwiigui/gui.h" #include "libwiigui/gui_diskcover.h" +#include "libwiigui/Text.hpp" #include "network/networkops.h" #include "network/http.h" #include "prompts/PromptWindows.h" @@ -71,9 +72,9 @@ extern void HaltGui(); ***************************************************************************/ int OnScreenNumpad(char * var, u32 maxlen) { int save = -1; - + GuiNumpad numpad(var, maxlen); - + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); // because destroy GuiSound must wait while sound playing is finished, we use a global sound if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size,Settings.sfxvolume); @@ -104,7 +105,7 @@ int OnScreenNumpad(char * var, u32 maxlen) { GuiButton cancelBtn(&cancelBtnImg,&cancelBtnImg, 1, 4, -5, -15, &trigA, &btnSoundOver, btnClick2,1); cancelBtn.SetLabel(&cancelBtnTxt); cancelBtn.SetTrigger(&trigB); - + numpad.Append(&okBtn); numpad.Append(&cancelBtn); @@ -132,7 +133,7 @@ int OnScreenNumpad(char * var, u32 maxlen) { mainWindow->SetState(STATE_DEFAULT); ResumeGui(); gprintf("\t%s",(save == 1?"saved":"discarded")); - return save; + return save; } /**************************************************************************** @@ -299,7 +300,7 @@ void WindowCredits() { i++; y+=26; - GuiText::SetPresets(22, (GXColor) {255, 255, 255, 255}, 0, GuiText::WRAP,FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP, ALIGN_LEFT, ALIGN_TOP); + GuiText::SetPresets(22, (GXColor) {255, 255, 255, 255}, 3000, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP, ALIGN_LEFT, ALIGN_TOP); txt[i] = new GuiText(tr("Coding:")); txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); @@ -1159,7 +1160,7 @@ int GameWindowPrompt() { GuiText nameTxt("", 22, THEME.prompttext); if (Settings.wsprompt == yes) nameTxt.SetWidescreen(CFG.widescreen); - nameTxt.SetMaxWidth(350, GuiText::SCROLL); + nameTxt.SetMaxWidth(350, SCROLL_HORIZONTAL); GuiButton nameBtn(120,50); nameBtn.SetLabel(&nameTxt); // nameBtn.SetLabelOver(&nameTxt); @@ -1174,7 +1175,7 @@ int GameWindowPrompt() { nameBtn.SetEffectGrow(); } - GuiText sizeTxt(NULL, 22, THEME.prompttext); //TODO: get the size here + GuiText sizeTxt((char*) NULL, 22, THEME.prompttext); //TODO: get the size here sizeTxt.SetAlignment(ALIGN_RIGHT, ALIGN_TOP); sizeTxt.SetPosition(-60,70); @@ -1190,7 +1191,7 @@ int GameWindowPrompt() { diskImg2.SetAngle(angle); diskImg2.SetBeta(180); - GuiText playcntTxt(NULL, 18, THEME.info); + GuiText playcntTxt((char*) NULL, 18, THEME.info); playcntTxt.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); playcntTxt.SetPosition(-115,45); @@ -1295,7 +1296,7 @@ int GameWindowPrompt() { promptWindow.Append(&diskImg2); promptWindow.Append(&btn1); - + short changed = -1; GuiImageData * diskCover = NULL; GuiImageData * diskCover2 = NULL; @@ -1746,7 +1747,7 @@ DiscWait(const char *title, const char *msg, const char *btn1Label, const char * } } - GuiText timerTxt(NULL, 26, THEME.prompttext); + GuiText timerTxt((char*) NULL, 26, THEME.prompttext); timerTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); timerTxt.SetPosition(0,160); @@ -2143,15 +2144,15 @@ ProgressDownloadWindow(int choice2) { titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); titleTxt.SetPosition(0,60); - GuiText msgTxt(NULL, 20, THEME.prompttext); + GuiText msgTxt((char*) NULL, 20, THEME.prompttext); msgTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); msgTxt.SetPosition(0,130); - GuiText msg2Txt(NULL, 26, THEME.prompttext); + GuiText msg2Txt((char*) NULL, 26, THEME.prompttext); msg2Txt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); msg2Txt.SetPosition(0,100); - GuiText prTxt(NULL, 26, THEME.prompttext); + GuiText prTxt((char*) NULL, 26, THEME.prompttext); prTxt.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); prTxt.SetPosition(0, 40); @@ -2768,7 +2769,7 @@ int ProgressUpdateWindow() { } else { filesize = download_request("http://www.techjawa.com/usbloadergx/ULNR.file");//for some reason it didn't download completely when saved as a wad. } - + if (filesize > 0) { pfile = fopen(dolpath, "wb");//here we save the txt as a wad @@ -2889,7 +2890,7 @@ int ProgressUpdateWindow() { return 1; } -#else +#else int ProgressUpdateWindow() { gprintf("\nProgressUpdateWindow(not full channel)"); @@ -2954,7 +2955,7 @@ int ProgressUpdateWindow() { msg2Txt.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); msg2Txt.SetPosition(0, 50); - GuiText prTxt(NULL, 26, THEME.prompttext); + GuiText prTxt((char*) NULL, 26, THEME.prompttext); prTxt.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); prTxt.SetPosition(0, 7); @@ -3053,7 +3054,7 @@ int ProgressUpdateWindow() { promptWindow.Append(&progressbarOutlineImg); promptWindow.Append(&prTxt); msgTxt.SetTextf("%s Rev%i", tr("Update to"), newrev); - + s32 filesize; if (Settings.beta_upgrades) { char url[255]; @@ -3487,7 +3488,7 @@ HBCWindowPrompt(const char *name, const char *coder, const char *version, GuiText nameTxt(name,30 , THEME.prompttext); nameTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); nameTxt.SetPosition(0,-15); - nameTxt.SetMaxWidth(430, GuiText::SCROLL); + nameTxt.SetMaxWidth(430, SCROLL_HORIZONTAL); if (strcmp(coder,"")) @@ -3512,11 +3513,11 @@ HBCWindowPrompt(const char *name, const char *coder, const char *version, release_dateTxt.SetMaxWidth(430); int pagesize = 6; - GuiText long_descriptionTxt(long_description, 20, THEME.prompttext); + Text long_descriptionTxt(long_description, 20, THEME.prompttext); long_descriptionTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); long_descriptionTxt.SetPosition(46,117); long_descriptionTxt.SetMaxWidth(360); - long_descriptionTxt.SetNumLines(pagesize); + long_descriptionTxt.SetLinesToDraw(pagesize); //convert filesize from u64 to char and put unit of measurement after it char temp2[7]; @@ -3623,18 +3624,17 @@ HBCWindowPrompt(const char *name, const char *coder, const char *version, gprintf("...It's easy, mmmmmmKay"); } else if ((arrowUpBtn.GetState()==STATE_CLICKED||arrowUpBtn.GetState()==STATE_HELD) ) { - if (long_descriptionTxt.GetFirstLine()>1) - long_descriptionTxt.SetFirstLine(long_descriptionTxt.GetFirstLine()-1); + long_descriptionTxt.SetTextLine(long_descriptionTxt.GetCurrPos()-1); usleep(60000); if (!((ButtonsHold() & WPAD_BUTTON_UP)||(ButtonsHold() & PAD_BUTTON_UP))) arrowUpBtn.ResetState(); } else if ((arrowDownBtn.GetState()==STATE_CLICKED||arrowDownBtn.GetState()==STATE_HELD) - &&long_descriptionTxt.GetTotalLines()>pagesize - &&long_descriptionTxt.GetFirstLine()-1pagesize + &&long_descriptionTxt.GetCurrPos()-1rootdir, browser->dir); AdressText.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); AdressText.SetPosition(20, 0); - AdressText.SetMaxWidth(Address.GetWidth()-40, GuiText::SCROLL); + AdressText.SetMaxWidth(Address.GetWidth()-40, SCROLL_HORIZONTAL); GuiImage AdressbarImg(&Address); GuiButton Adressbar(Address.GetWidth(), Address.GetHeight()); Adressbar.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); diff --git a/source/prompts/gameinfo.cpp b/source/prompts/gameinfo.cpp index c6c356df..112b5a93 100644 --- a/source/prompts/gameinfo.cpp +++ b/source/prompts/gameinfo.cpp @@ -8,6 +8,7 @@ #include "usbloader/wbfs.h" #include "language/gettext.h" #include "libwiigui/gui.h" +#include "libwiigui/Text.hpp" #include "../xml/xml.h" #include "menu.h" #include "menu/menus.h" @@ -126,7 +127,7 @@ int showGameInfo(char *ID) { GuiText * publisherTxt = NULL; GuiText * developerTxt = NULL; GuiText * titleTxt = NULL; - GuiText * synopsisTxt = NULL; + Text * synopsisTxt = NULL; GuiText ** genreTxt = NULL; GuiText ** wifiTxt = NULL; GuiText * wiitdb1Txt = NULL; @@ -594,7 +595,7 @@ int showGameInfo(char *ID) { if (strcmp(gameinfo.title,"") != 0) { snprintf(linebuf, sizeof(linebuf), "%s",gameinfo.title); titleTxt = new GuiText(linebuf, titlefontsize, (GXColor) {0,0,0, 255}); - titleTxt->SetMaxWidth(350, GuiText::SCROLL); + titleTxt->SetMaxWidth(350, SCROLL_HORIZONTAL); //while (titleTxt->GetWidth()>250) { titleTxt->SetFontSize(titlefontsize-=2); } titleTxt->SetAlignment(ALIGN_CENTRE, ALIGN_TOP); titleTxt->SetPosition(txtXOffset,12+titley); @@ -662,7 +663,7 @@ int showGameInfo(char *ID) { snprintf(linebuf, sizeof(linebuf), "%s %s", tr("Published by"), gameinfo.publisher); publisherTxt = new GuiText(linebuf, 16, (GXColor) {0,0,0, 255}); if (publisherTxt->GetWidth()>250) newline=2; - publisherTxt->SetMaxWidth(250,GuiText::WRAP); + publisherTxt->SetMaxWidth(250, WRAP); publisherTxt->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); publisherTxt->SetPosition(-17,12+indexy); indexy+=(20 * newline); @@ -675,7 +676,7 @@ int showGameInfo(char *ID) { snprintf(linebuf, sizeof(linebuf), "%s %s", tr("Developed by"), gameinfo.developer); developerTxt = new GuiText(linebuf, 16, (GXColor) {0,0,0, 255}); if (developerTxt->GetWidth()>250) newline=2; - developerTxt->SetMaxWidth(250,GuiText::WRAP); + developerTxt->SetMaxWidth(250, WRAP); developerTxt->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); developerTxt->SetPosition(-17,12+indexy); indexy+=(20 * newline); @@ -723,11 +724,11 @@ int showGameInfo(char *ID) { int pagesize=12; if (strcmp(gameinfo.synopsis,"") !=0) { snprintf(linebuf, sizeof(linebuf), "%s", gameinfo.synopsis); - synopsisTxt = new GuiText(linebuf, 16, (GXColor) {0,0,0, 255}); - synopsisTxt->SetMaxWidth(350,GuiText::WRAP); + synopsisTxt = new Text(linebuf, 16, (GXColor) {0,0,0, 255}); + synopsisTxt->SetMaxWidth(350); synopsisTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); synopsisTxt->SetPosition(0,0); - synopsisTxt->SetNumLines(pagesize); + synopsisTxt->SetLinesToDraw(pagesize); //synopsisTxt->SetFirstLine(12); dialogBoxImg11 = new GuiImage(&dialogBox1); @@ -864,22 +865,22 @@ int showGameInfo(char *ID) { } else if ((upBtn.GetState()==STATE_CLICKED||upBtn.GetState()==STATE_HELD) && page==2) { //int l=synopsisTxt->GetFirstLine()-1; - if (synopsisTxt->GetFirstLine()>1) - synopsisTxt->SetFirstLine(synopsisTxt->GetFirstLine()-1); + if (synopsisTxt->GetCurrPos()>1) + synopsisTxt->SetTextLine(synopsisTxt->GetCurrPos()-1); usleep(60000); if (!((ButtonsHold() & WPAD_BUTTON_UP)||(ButtonsHold() & PAD_BUTTON_UP))) upBtn.ResetState(); } else if ((dnBtn.GetState()==STATE_CLICKED||dnBtn.GetState()==STATE_HELD) && page==2 - &&synopsisTxt->GetTotalLines()>pagesize - &&synopsisTxt->GetFirstLine()-1GetTotalLines()-pagesize) { + &&synopsisTxt->GetTotalLinesCount()>pagesize + &&synopsisTxt->GetCurrPos()-1GetTotalLinesCount()-pagesize) { int l=0; //if(synopsisTxt->GetTotalLines()>pagesize) - l=synopsisTxt->GetFirstLine()+1; + l=synopsisTxt->GetCurrPos()+1; //if (l>(synopsisTxt->GetTotalLines()+1)-pagesize) //l=(synopsisTxt->GetTotalLines()+1)-pagesize; - synopsisTxt->SetFirstLine(l); + synopsisTxt->SetTextLine(l); usleep(60000); if (!((ButtonsHold() & WPAD_BUTTON_DOWN)||(ButtonsHold() & PAD_BUTTON_DOWN))) dnBtn.ResetState(); diff --git a/source/settings/Settings.cpp b/source/settings/Settings.cpp index 29e899b5..3281d9f3 100644 --- a/source/settings/Settings.cpp +++ b/source/settings/Settings.cpp @@ -2275,7 +2275,7 @@ int GameSettings(struct discHdr * header) GuiText titleTxt(!mountMethod?get_title(header):gameName, 28, (GXColor) {0, 0, 0, 255}); titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); titleTxt.SetPosition(12,40); - titleTxt.SetMaxWidth(356, GuiText::SCROLL); + titleTxt.SetMaxWidth(356, SCROLL_HORIZONTAL); GuiImage settingsbackground(&settingsbg); diff --git a/source/themes/Theme_Downloader.cpp b/source/themes/Theme_Downloader.cpp index b1d00630..bb00dbe8 100644 --- a/source/themes/Theme_Downloader.cpp +++ b/source/themes/Theme_Downloader.cpp @@ -182,7 +182,7 @@ static int Theme_Prompt(const char *title, const char *author, GuiImageData *thu GuiText titleTxt2(title, 18, THEME.prompttext); titleTxt2.SetAlignment(ALIGN_LEFT, ALIGN_TOP); titleTxt2.SetPosition(230, 50); - titleTxt2.SetMaxWidth(dialogBox.GetWidth()-220, GuiText::WRAP); + titleTxt2.SetMaxWidth(dialogBox.GetWidth()-220, WRAP); GuiText authorTxt(tr("Author:"), 18, THEME.prompttext); authorTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); @@ -191,7 +191,7 @@ static int Theme_Prompt(const char *title, const char *author, GuiImageData *thu GuiText authorTxt2(author, 18, THEME.prompttext); authorTxt2.SetAlignment(ALIGN_LEFT, ALIGN_TOP); authorTxt2.SetPosition(230, 120); - authorTxt2.SetMaxWidth(dialogBox.GetWidth()-220, GuiText::DOTTED); + authorTxt2.SetMaxWidth(dialogBox.GetWidth()-220, DOTTED); GuiText downloadBtnTxt(tr("Download") , 22, THEME.prompttext); downloadBtnTxt.SetMaxWidth(btnOutline.GetWidth()-30); @@ -417,7 +417,7 @@ int Theme_Downloader() GoRightBtn.SetTrigger(&trigPlus); GuiImage PageindicatorImg(&PageindicatorImgData); - GuiText PageindicatorTxt(NULL, 22, (GXColor) { 0, 0, 0, 255}); + GuiText PageindicatorTxt((char *) NULL, 22, (GXColor) { 0, 0, 0, 255}); GuiButton PageIndicatorBtn(PageindicatorImg.GetWidth(), PageindicatorImg.GetHeight()); PageIndicatorBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); PageIndicatorBtn.SetPosition(110, 400); @@ -518,7 +518,7 @@ int Theme_Downloader() MainButtonTxt[n] = new GuiText(Theme->GetThemeTitle(i), 18, (GXColor) { 0, 0, 0, 255}); MainButtonTxt[n]->SetAlignment(ALIGN_CENTER, ALIGN_TOP); MainButtonTxt[n]->SetPosition(0, 10); - MainButtonTxt[n]->SetMaxWidth(theme_box_Data.GetWidth()-10, GuiText::DOTTED); + MainButtonTxt[n]->SetMaxWidth(theme_box_Data.GetWidth()-10, DOTTED); sprintf(url, "%s", Theme->GetImageLink(i)); diff --git a/source/usbloader/getentries.cpp b/source/usbloader/getentries.cpp index e19c83de..8d0fb44a 100644 --- a/source/usbloader/getentries.cpp +++ b/source/usbloader/getentries.cpp @@ -225,7 +225,7 @@ int __Menu_GetPrevFilter(int t, wchar_t* gameFilter, u32 gameFiltered, wchar_t * } } - wchar_t *wname = FreeTypeGX::charToWideChar(get_title(header)); + wchar_t *wname = charToWideChar(get_title(header)); if(wname) nameList.push_back(wname); } @@ -268,7 +268,7 @@ int __Menu_GetGameFilter_NextList(discHdr *gameList, u32 gameCnt, wchar_t **Pgam for(i=0; i filter_len) @@ -439,7 +439,7 @@ int buildTitleList(int t, wchar_t* gameFilter, discHdr ** PgameList, u32 *PgameC if(gameFilter && *gameFilter) { u32 filter_len = wcslen(gameFilter); - wchar_t *gameName = FreeTypeGX::charToWideChar(get_title(header)); + wchar_t *gameName = charToWideChar(get_title(header)); if (!gameName || wcsnicmp(gameName, gameFilter, filter_len)) { delete [] gameName; continue; @@ -541,7 +541,7 @@ int __Menu_GetGameList(int t, wchar_t* gameFilter, discHdr ** PgameList, u32 *Pg if(gameFilter && *gameFilter && t==0) { u32 filter_len = wcslen(gameFilter); - wchar_t *gameName = FreeTypeGX::charToWideChar(get_title(header)); + wchar_t *gameName = charToWideChar(get_title(header)); if (!gameName || wcsnicmp(gameName, gameFilter, filter_len)) { delete [] gameName; continue; diff --git a/source/usbloader/wbfs.cpp b/source/usbloader/wbfs.cpp index 6d9e58b5..0b4fea64 100644 --- a/source/usbloader/wbfs.cpp +++ b/source/usbloader/wbfs.cpp @@ -1,263 +1,290 @@ -#include - -#include "wbfs.h" -#include "usbloader/wbfs/wbfs_base.h" -#include "usbloader/wbfs/wbfs_wbfs.h" -#include "usbloader/wbfs/wbfs_fat.h" -#include "usbloader/wbfs/wbfs_ntfs.h" - -#include "usbloader/partition_usbloader.h" -#include "usbloader/getentries.h" -#include "gecko.h" - -Wbfs *current = NULL; -#define DEBUG_WBFS - -/* WBFS device */ -s32 wbfsDev = WBFS_MIN_DEVICE; - -// partition -char wbfs_fs_drive[16]; -int wbfs_part_fs = PART_FS_WBFS; -u32 wbfs_part_idx = 0; -u32 wbfs_part_lba = 0; - -wbfs_disc_t* WBFS_OpenDisc(u8 *discid) { - return current->OpenDisc(discid); -} - -void WBFS_CloseDisc(wbfs_disc_t *disc) { - current->CloseDisc(disc); -} - -wbfs_t *GetHddInfo(void) { - return current->GetHddInfo(); -} - -s32 WBFS_Init(u32 device) { - return Wbfs::Init(device); -} - -s32 WBFS_Open(void) { - WBFS_Close(); - - current = new Wbfs_Wbfs(WBFS_DEVICE_USB, 0, 0); // Fix me! - - wbfs_part_fs = wbfs_part_idx = wbfs_part_lba = 0; - wbfs_part_idx = 1; - - return current->Open(); -} - -s32 WBFS_OpenPart(u32 part_fs, u32 part_idx, u32 part_lba, u32 part_size, char *partition) -{ - // close - WBFS_Close(); - - if (part_fs == PART_FS_FAT) { - current = new Wbfs_Fat(wbfsDev, part_lba, part_size); - strcpy(wbfs_fs_drive, "USB:"); -#ifdef DEBUG_WBFS - gprintf("\n\tCreated WBFS_Fat instance at lba: %d of size %d", part_lba, part_size); -#endif - } else if (part_fs == PART_FS_NTFS) { - current = new Wbfs_Ntfs(wbfsDev, part_lba, part_size); - strcpy(wbfs_fs_drive, "NTFS:"); -#ifdef DEBUG_WBFS - gprintf("\n\tCreated WBFS_Ntfs instance at lba: %d of size %d", part_lba, part_size); -#endif - } else { - current = new Wbfs_Wbfs(wbfsDev, part_lba, part_size); -#ifdef DEBUG_WBFS - gprintf("\n\tCreated WBFS_Wbfs instance at lba: %d of size %d", part_lba, part_size); -#endif - } - if (current->Open()) - { - delete current; - current = NULL; - return -1; - } - - // success - wbfs_part_fs = part_fs; - wbfs_part_idx = part_idx; - wbfs_part_lba = part_lba; - - const char *fs = "WBFS"; - if (wbfs_part_fs == PART_FS_FAT) fs = "FAT"; - if (wbfs_part_fs == PART_FS_NTFS) fs = "NTFS"; - sprintf(partition, "%s%d", fs, wbfs_part_idx); - return 0; -} - -s32 WBFS_OpenNamed(char *partition) -{ - u32 i; - u32 part_fs = PART_FS_WBFS; - u32 part_idx = 0; - u32 part_lba = 0; - s32 ret = 0; - PartList plist; - - // close - WBFS_Close(); - - // parse partition option - if (strncasecmp(partition, "WBFS", 4) == 0) { - i = atoi(partition+4); - if (i < 1 || i > 4) goto err; - part_fs = PART_FS_WBFS; - part_idx = i; - } else if (strncasecmp(partition, "FAT", 3) == 0) { - if (wbfsDev != WBFS_DEVICE_USB) goto err; - i = atoi(partition+3); - if (i < 1 || i > 9) goto err; - part_fs = PART_FS_FAT; - part_idx = i; - } else if (strncasecmp(partition, "NTFS", 4) == 0) { - i = atoi(partition+4); - if (i < 1 || i > 9) goto err; - part_fs = PART_FS_NTFS; - part_idx = i; - } else { - goto err; - } - - // Get partition entries - ret = Partition_GetList(wbfsDev, &plist); - if (ret || plist.num == 0) return -1; - - if (part_fs == PART_FS_WBFS) { - if (part_idx > plist.wbfs_n) goto err; - for (i=0; i plist.fat_n) goto err; - for (i=0; i plist.ntfs_n) goto err; - for (i=0; i= plist.num) goto err; - // set partition lba sector - part_lba = plist.pentry[i].sector; - - if (WBFS_OpenPart(part_fs, part_idx, part_lba, plist.pentry[i].size, partition)) { - goto err; - } - // success - return 0; -err: - return -1; -} - -s32 WBFS_OpenLBA(u32 lba, u32 size) -{ - Wbfs *part = new Wbfs_Wbfs(wbfsDev, lba, size); - if (part->Open() != 0) - { - delete part; - return -1; - } - - WBFS_Close(); - current = part; - return 0; -} - -bool WBFS_Close(void) -{ - if (current != NULL) { - current->Close(); - delete current; - current = NULL; - } - - wbfs_part_fs = 0; - wbfs_part_idx = 0; - wbfs_part_lba = 0; - wbfs_fs_drive[0] = '\0'; - - ResetGamelist(); - - return 0; -} - -bool WBFS_Mounted() -{ - return (current != NULL && current->Mounted()); -} - -s32 WBFS_Format(u32 lba, u32 size) { - return current->Format(); -} - -s32 WBFS_GetCount(u32 *count) { - return current->GetCount(count); -} - -s32 WBFS_GetHeaders(struct discHdr *outbuf, u32 cnt, u32 len) { - return current->GetHeaders(outbuf, cnt, len); -} - -s32 WBFS_CheckGame(u8 *discid) { - return current->CheckGame(discid); -} - -s32 WBFS_AddGame(void) { - s32 retval = current->AddGame(); - if (retval == 0) { - ResetGamelist(); - } - return retval; -} - -s32 WBFS_RemoveGame(u8 *discid) { - s32 retval = current->RemoveGame(discid); - if (retval == 0) { - ResetGamelist(); - } - return retval; -} - -s32 WBFS_GameSize(u8 *discid, f32 *size) { - return current->GameSize(discid, size); -} - -s32 WBFS_DiskSpace(f32 *used, f32 *free) { - return current->DiskSpace(used, free); -} - -s32 WBFS_RenameGame(u8 *discid, const void *newname) { - s32 retval = current->RenameGame(discid, newname); - if (retval == 0) { - ResetGamelist(); - } - return retval; -} - -s32 WBFS_ReIDGame(u8 *discid, const void *newID) { - s32 retval = current->ReIDGame(discid, newID); - if (retval == 0) { - ResetGamelist(); - } - return retval; -} - -f32 WBFS_EstimeGameSize(void) { - return current->EstimateGameSize(); -} - -int WBFS_GetFragList(u8 *id) { - return current->GetFragList(id); -} - -bool WBFS_ShowFreeSpace(void) { - return current->ShowFreeSpace(); -} +#include +#include +#include + +#include "usbloader/usbstorage2.h" +#include "fatmounter.h" +#include "wbfs.h" +#include "usbloader/wbfs/wbfs_base.h" +#include "usbloader/wbfs/wbfs_wbfs.h" +#include "usbloader/wbfs/wbfs_fat.h" +#include "usbloader/wbfs/wbfs_ntfs.h" + +#include "usbloader/partition_usbloader.h" +#include "usbloader/getentries.h" +#include "gecko.h" + +Wbfs *current = NULL; +#define DEBUG_WBFS + +/* WBFS device */ +s32 wbfsDev = WBFS_MIN_DEVICE; + +// partition +char wbfs_fs_drive[16]; +int wbfs_part_fs = PART_FS_WBFS; +u32 wbfs_part_idx = 0; +u32 wbfs_part_lba = 0; + +wbfs_disc_t* WBFS_OpenDisc(u8 *discid) { + return current->OpenDisc(discid); +} + +void WBFS_CloseDisc(wbfs_disc_t *disc) { + current->CloseDisc(disc); +} + +wbfs_t *GetHddInfo(void) { + return current->GetHddInfo(); +} + +s32 WBFS_Init(u32 device) { + return Wbfs::Init(device); +} + +s32 WBFS_Open(void) { + WBFS_Close(); + + current = new Wbfs_Wbfs(WBFS_DEVICE_USB, 0, 0); // Fix me! + + wbfs_part_fs = wbfs_part_idx = wbfs_part_lba = 0; + wbfs_part_idx = 1; + + return current->Open(); +} + +s32 WBFS_OpenPart(u32 part_fs, u32 part_idx, u32 part_lba, u32 part_size, char *partition) +{ + // close + WBFS_Close(); + + if (part_fs == PART_FS_FAT) { + current = new Wbfs_Fat(wbfsDev, part_lba, part_size); + strcpy(wbfs_fs_drive, "USB:"); +#ifdef DEBUG_WBFS + gprintf("\n\tCreated WBFS_Fat instance at lba: %d of size %d", part_lba, part_size); +#endif + } else if (part_fs == PART_FS_NTFS) { + current = new Wbfs_Ntfs(wbfsDev, part_lba, part_size); + strcpy(wbfs_fs_drive, "NTFS:"); +#ifdef DEBUG_WBFS + gprintf("\n\tCreated WBFS_Ntfs instance at lba: %d of size %d", part_lba, part_size); +#endif + } else { + current = new Wbfs_Wbfs(wbfsDev, part_lba, part_size); +#ifdef DEBUG_WBFS + gprintf("\n\tCreated WBFS_Wbfs instance at lba: %d of size %d", part_lba, part_size); +#endif + } + if (current->Open()) + { + delete current; + current = NULL; + return -1; + } + + // success + wbfs_part_fs = part_fs; + wbfs_part_idx = part_idx; + wbfs_part_lba = part_lba; + + const char *fs = "WBFS"; + if (wbfs_part_fs == PART_FS_FAT) fs = "FAT"; + if (wbfs_part_fs == PART_FS_NTFS) fs = "NTFS"; + sprintf(partition, "%s%d", fs, wbfs_part_idx); + return 0; +} + +s32 WBFS_OpenNamed(char *partition) +{ + u32 i; + u32 part_fs = PART_FS_WBFS; + u32 part_idx = 0; + u32 part_lba = 0; + s32 ret = 0; + PartList plist; + + // close + WBFS_Close(); + + // parse partition option + if (strncasecmp(partition, "WBFS", 4) == 0) { + i = atoi(partition+4); + if (i < 1 || i > 4) goto err; + part_fs = PART_FS_WBFS; + part_idx = i; + } else if (strncasecmp(partition, "FAT", 3) == 0) { + if (wbfsDev != WBFS_DEVICE_USB) goto err; + i = atoi(partition+3); + if (i < 1 || i > 9) goto err; + part_fs = PART_FS_FAT; + part_idx = i; + } else if (strncasecmp(partition, "NTFS", 4) == 0) { + i = atoi(partition+4); + if (i < 1 || i > 9) goto err; + part_fs = PART_FS_NTFS; + part_idx = i; + } else { + goto err; + } + + // Get partition entries + ret = Partition_GetList(wbfsDev, &plist); + if (ret || plist.num == 0) return -1; + + if (part_fs == PART_FS_WBFS) { + if (part_idx > plist.wbfs_n) goto err; + for (i=0; i plist.fat_n) goto err; + for (i=0; i plist.ntfs_n) goto err; + for (i=0; i= plist.num) goto err; + // set partition lba sector + part_lba = plist.pentry[i].sector; + + if (WBFS_OpenPart(part_fs, part_idx, part_lba, plist.pentry[i].size, partition)) { + goto err; + } + // success + return 0; +err: + return -1; +} + +s32 WBFS_OpenLBA(u32 lba, u32 size) +{ + Wbfs *part = new Wbfs_Wbfs(wbfsDev, lba, size); + if (part->Open() != 0) + { + delete part; + return -1; + } + + WBFS_Close(); + current = part; + return 0; +} + +bool WBFS_Close(void) +{ + if (current != NULL) { + current->Close(); + delete current; + current = NULL; + } + + wbfs_part_fs = 0; + wbfs_part_idx = 0; + wbfs_part_lba = 0; + wbfs_fs_drive[0] = '\0'; + + ResetGamelist(); + + return 0; +} + +bool WBFS_Mounted() +{ + return (current != NULL && current->Mounted()); +} + +s32 WBFS_Format(u32 lba, u32 size) { + return current->Format(); +} + +s32 WBFS_GetCount(u32 *count) { + return current->GetCount(count); +} + +s32 WBFS_GetHeaders(struct discHdr *outbuf, u32 cnt, u32 len) { + return current->GetHeaders(outbuf, cnt, len); +} + +s32 WBFS_CheckGame(u8 *discid) { + return current->CheckGame(discid); +} + +s32 WBFS_AddGame(void) { + s32 retval = current->AddGame(); + if (retval == 0) { + ResetGamelist(); + } + return retval; +} + +s32 WBFS_RemoveGame(u8 *discid) { + s32 retval = current->RemoveGame(discid); + if (retval == 0) { + ResetGamelist(); + } + return retval; +} + +s32 WBFS_GameSize(u8 *discid, f32 *size) { + return current->GameSize(discid, size); +} + +s32 WBFS_DiskSpace(f32 *used, f32 *free) { + return current->DiskSpace(used, free); +} + +s32 WBFS_RenameGame(u8 *discid, const void *newname) { + s32 retval = current->RenameGame(discid, newname); + if (retval == 0) { + ResetGamelist(); + } + return retval; +} + +s32 WBFS_ReIDGame(u8 *discid, const void *newID) { + s32 retval = current->ReIDGame(discid, newID); + if (retval == 0) { + ResetGamelist(); + } + return retval; +} + +f32 WBFS_EstimeGameSize(void) { + return current->EstimateGameSize(); +} + +int WBFS_GetFragList(u8 *id) { + return current->GetFragList(id); +} + +bool WBFS_ShowFreeSpace(void) { + return current->ShowFreeSpace(); +} + +int MountWBFS() +{ + int ret = -1; + time_t currTime = time(0); + + while(time(0)-currTime < 15) + { + USBDevice_deInit(); + USBStorage2_Deinit(); + USBDevice_Init(); + ret = WBFS_Init(WBFS_DEVICE_USB); + printf("%i...", int(time(0)-currTime)); + if(ret < 0) + sleep(1); + else + break; + } + + printf("\n"); + + return ret; +} diff --git a/source/usbloader/wbfs.h b/source/usbloader/wbfs.h index 96c2068c..9e19df4a 100644 --- a/source/usbloader/wbfs.h +++ b/source/usbloader/wbfs.h @@ -54,6 +54,7 @@ extern "C" { bool WBFS_Close(); bool WBFS_Mounted(); bool WBFS_Selected(); + int MountWBFS(); #ifdef __cplusplus diff --git a/source/wad/wad.cpp b/source/wad/wad.cpp index 56f353ed..636ceb6e 100644 --- a/source/wad/wad.cpp +++ b/source/wad/wad.cpp @@ -179,27 +179,27 @@ s32 Wad_Install(FILE *fp) char msg[50]; sprintf(msg, " "); // sprintf(msg, "%s", tr("Initializing Network")); - GuiText msg1Txt(NULL, 20, THEME.prompttext); + GuiText msg1Txt((char*)NULL, 20, THEME.prompttext); msg1Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg1Txt.SetPosition(50,75); // char msg2[50] = " "; - GuiText msg2Txt(NULL, 20, THEME.prompttext); + GuiText msg2Txt((char*)NULL, 20, THEME.prompttext); msg2Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg2Txt.SetPosition(50, 98); - GuiText msg3Txt(NULL, 20, THEME.prompttext); + GuiText msg3Txt((char*)NULL, 20, THEME.prompttext); msg3Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg3Txt.SetPosition(50, 121); - GuiText msg4Txt(NULL, 20, THEME.prompttext); + GuiText msg4Txt((char*)NULL, 20, THEME.prompttext); msg4Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg4Txt.SetPosition(50, 144); - GuiText msg5Txt(NULL, 20, THEME.prompttext); + GuiText msg5Txt((char*)NULL, 20, THEME.prompttext); msg5Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg5Txt.SetPosition(50, 167); - GuiText prTxt(NULL, 26, THEME.prompttext); + GuiText prTxt((char*)NULL, 26, THEME.prompttext); prTxt.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); prTxt.SetPosition(0, 50); @@ -487,23 +487,23 @@ s32 Wad_Uninstall(FILE *fp) titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); titleTxt.SetPosition(0,40); - GuiText msg1Txt(NULL, 18, THEME.prompttext); + GuiText msg1Txt((char*)NULL, 18, THEME.prompttext); msg1Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg1Txt.SetPosition(50,75); - GuiText msg2Txt(NULL, 18, THEME.prompttext); + GuiText msg2Txt((char*)NULL, 18, THEME.prompttext); msg2Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg2Txt.SetPosition(50, 98); - GuiText msg3Txt(NULL, 18, THEME.prompttext); + GuiText msg3Txt((char*)NULL, 18, THEME.prompttext); msg3Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg3Txt.SetPosition(50, 121); - GuiText msg4Txt(NULL, 18, THEME.prompttext); + GuiText msg4Txt((char*)NULL, 18, THEME.prompttext); msg4Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg4Txt.SetPosition(50, 144); - GuiText msg5Txt(NULL, 18, THEME.prompttext); + GuiText msg5Txt((char*)NULL, 18, THEME.prompttext); msg5Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg5Txt.SetPosition(50, 167); diff --git a/source/wstring.cpp b/source/wstring.cpp new file mode 100644 index 00000000..778000a2 --- /dev/null +++ b/source/wstring.cpp @@ -0,0 +1,151 @@ +#include "wstring.hpp" + +using namespace std; + +wString::wString(const wchar_t *s) : + std::basic_string, std::allocator >(s) +{ +} + +wString::wString(const basic_string, allocator > &ws) : + basic_string, allocator >(ws) +{ +} + +wString::wString(const string &s) +{ + std::string::size_type size; + + size = s.size(); + resize(size); + for (std::string::size_type i = 0; i < size; ++i) + (*this)[i] = (unsigned char)s[i]; +} + +wString &wString::operator=(const string &s) +{ + std::string::size_type size; + + size = s.size(); + this->resize(size); + for (std::string::size_type i = 0; i < size; ++i) + (*this)[i] = (unsigned char)s[i]; + return *this; +} + +void wString::fromUTF8(const char *s) +{ + size_t len = utf8Len(s); + + clear(); + if (len == 0) + return; + reserve(len); + for (int i = 0; s[i] != 0; ) + { + if ((s[i] & 0xF8) == 0xF0) + { + push_back(((wchar_t)(s[i] & 0x07) << 18) | ((wchar_t)(s[i + 1] & 0x3F) << 12) | ((wchar_t)(s[i + 2] & 0x3F) << 6) | (wchar_t)(s[i + 3] & 0x3F)); + i += 4; + } + else if ((s[i] & 0xF0) == 0xE0) + { + push_back(((wchar_t)(s[i] & 0x0F) << 12) | ((wchar_t)(s[i + 1] & 0x3F) << 6) | (wchar_t)(s[i + 2] & 0x3F)); + i += 3; + } + else if ((s[i] & 0xE0) == 0xC0) + { + push_back(((wchar_t)(s[i] & 0x1F) << 6) | (wchar_t)(s[i + 1] & 0x3F)); + i += 2; + } + else + { + push_back((wchar_t)s[i]); + ++i; + } + } +} + +string wString::toUTF8(void) const +{ + string s; + size_t len = 0; + wchar_t wc; + + for (size_t i = 0; i < size(); ++i) + { + wc = operator[](i); + if (wc < 0x80) + ++len; + else if (wc < 0x800) + len += 2; + else if (wc < 0x10000) + len += 3; + else + len += 4; + } + s.reserve(len); + for (size_t i = 0; i < size(); ++i) + { + wc = operator[](i); + if (wc < 0x80) + s.push_back((char)wc); + else if (wc < 0x800) + { + s.push_back((char)((wc >> 6) | 0xC0)); + s.push_back((char)((wc & 0x3F) | 0x80)); + } + else if (wc < 0x10000) + { + s.push_back((char)((wc >> 12) | 0xE0)); + s.push_back((char)(((wc >> 6) & 0x3F) | 0x80)); + s.push_back((char)((wc & 0x3F) | 0x80)); + } + else + { + s.push_back((char)(((wc >> 18) & 0x07) | 0xF0)); + s.push_back((char)(((wc >> 12) & 0x3F) | 0x80)); + s.push_back((char)(((wc >> 6) & 0x3F) | 0x80)); + s.push_back((char)((wc & 0x3F) | 0x80)); + } + } + return s; +} + +size_t utf8Len(const char *s) +{ + size_t len = 0; + + for (int i = 0; s[i] != 0; ) + { + if ((s[i] & 0xF8) == 0xF0) + { + if (((s[i + 1] & 0xC0) != 0x80) || ((s[i + 2] & 0xC0) != 0x80) || ((s[i + 3] & 0xC0) != 0x80)) + return 0; + ++len; + i += 4; + } + else if ((s[i] & 0xF0) == 0xE0) + { + if (((s[i + 1] & 0xC0) != 0x80) || ((s[i + 2] & 0xC0) != 0x80)) + return 0; + ++len; + i += 3; + } + else if ((s[i] & 0xE0) == 0xC0) + { + if (((s[i + 1] & 0xC0) != 0x80)) + return 0; + ++len; + i += 2; + } + else if ((s[i] & 0x80) == 0x00) + { + ++len; + ++i; + } + else + return 0; + } + return len; +} diff --git a/source/wstring.hpp b/source/wstring.hpp new file mode 100644 index 00000000..216294ad --- /dev/null +++ b/source/wstring.hpp @@ -0,0 +1,25 @@ +/**************************************************************************** + * wstring Class + * by Hibernatus + ***************************************************************************/ +#ifndef __WSTRING_HPP +#define __WSTRING_HPP + +#include + +class wString : public std::basic_string, std::allocator > +{ +public: + wString(void) { } + wString(const wchar_t *s); + wString(const std::basic_string, std::allocator > &ws); + wString(const std::string &s); + wString &operator=(const std::string &s); + void fromUTF8(const char *s); + std::string toUTF8(void) const; +}; + +size_t utf8Len(const char *s); + + +#endif // !defined(__WSTRING_HPP)