diff --git a/gui.pnproj b/gui.pnproj index 815801ea..211cf725 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/FreeTypeGX.cpp b/source/FreeTypeGX.cpp index dc8670b4..d97f6d69 100644 --- a/source/FreeTypeGX.cpp +++ b/source/FreeTypeGX.cpp @@ -1,788 +1,731 @@ -/* - * 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 - * - * This file is part of FreeTypeGX. - * - * FreeTypeGX is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * FreeTypeGX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with FreeTypeGX. If not, see . - */ - +/* + * 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 + * + * This file is part of FreeTypeGX. + * + * FreeTypeGX is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FreeTypeGX is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FreeTypeGX. If not, see . + */ + #include "FreeTypeGX.h" #include "CH2Unicode.h" #include "GB2Unicode.h" #include "main.h" -#include "cfg.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; - - -/** - * Default constructor for the FreeTypeGX class. - * - * @param textureFormat Optional format (GX_TF_*) of the texture as defined by the libogc gx.h header file. If not specified default value is GX_TF_RGBA8. - * @param vertexIndex Optional vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file. If not specified default value is GX_VTXFMT1. - */ -FreeTypeGX::FreeTypeGX(uint8_t textureFormat, uint8_t vertexIndex) { - FT_Init_FreeType(&this->ftLibrary); - - this->textureFormat = textureFormat; - this->setVertexFormat(vertexIndex); - this->setCompatibilityMode(FTGX_COMPATIBILITY_NONE); -} - -/** - * Default destructor for the FreeTypeGX class. - */ -FreeTypeGX::~FreeTypeGX() { - this->unloadFont(); -} - -/** - * Convert a short char sctring to a wide char string. - * - * This routine converts a supplied shot 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(char* strChar) { - wchar_t *strWChar; - strWChar = new wchar_t[strlen(strChar) + 1]; +#include "cfg.h" + + +/** + * Default constructor for the FreeTypeGX class. + * + * @param textureFormat Optional format (GX_TF_*) of the texture as defined by the libogc gx.h header file. If not specified default value is GX_TF_RGBA8. + * @param vertexIndex Optional vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file. If not specified default value is GX_VTXFMT1. + */ +FreeTypeGX::FreeTypeGX(uint8_t textureFormat, uint8_t vertexIndex) { + FT_Init_FreeType(&this->ftLibrary); + + this->textureFormat = textureFormat; + this->setVertexFormat(vertexIndex); + this->setCompatibilityMode(FTGX_COMPATIBILITY_NONE); +} + +/** + * Default destructor for the FreeTypeGX class. + */ +FreeTypeGX::~FreeTypeGX() { + this->unloadFont(); +} + +/** + * Convert a short char sctring to a wide char string. + * + * This routine converts a supplied shot 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(char* strChar) { + wchar_t *strWChar; + strWChar = new wchar_t[strlen(strChar) + 1]; if(Settings.unicodefix == 1) { CH2Unicode(strChar, strWChar); } else if(Settings.unicodefix == 2) { ConverGB2Unicode(strChar, strWChar); - } else { - char *tempSrc = strChar; - wchar_t *tempDest = strWChar; + } else { + char *tempSrc = strChar; + wchar_t *tempDest = strWChar; while((*tempDest++ = *tempSrc++)); } - - - return strWChar; -} - -/** - * - * \overload - */ -wchar_t* FreeTypeGX::charToWideChar(const char* strChar) { - return FreeTypeGX::charToWideChar((char*) strChar); -} - -/** - * Setup the vertex attribute formats for the glyph textures. - * - * This function sets up the vertex format for the glyph texture on the specified vertex format index. - * Note that this function should not need to be called except if the vertex formats are cleared or the specified - * vertex format index is modified. - * - * @param vertexIndex Vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file. -*/ -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); -} - -/** - * 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 fontBuffer A pointer in memory to a precompiled true type font buffer. - * @param bufferSize Size of the true type font buffer in bytes. - * @param pointSize The desired point size this wrapper's configured font face. - * @param cacheAll Optional flag to specify if all font characters should be cached when the class object is created. If specified as false the characters only become cached the first time they are used. If not specified default value is false. - */ -uint16_t FreeTypeGX::loadFont(uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll) { - this->unloadFont(); - this->ftPointSize = pointSize; - - FT_New_Memory_Face(this->ftLibrary, (FT_Byte *)fontBuffer, bufferSize, 0, &this->ftFace); - - if(this->ftPointSize > 0) - FT_Set_Pixel_Sizes(this->ftFace, 0, this->ftPointSize); - - this->ftSlot = this->ftFace->glyph; - this->ftKerningEnabled = FT_HAS_KERNING(this->ftFace); - - if (cacheAll) { - return this->cacheGlyphDataComplete(); - } - - return 0; -} - -/** - * - * \overload - */ -uint16_t FreeTypeGX::loadFont(const uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll) { - return this->loadFont((uint8_t *)fontBuffer, bufferSize, pointSize, cacheAll); -} - -/** - * Clears all loaded font glyph data. - * - * This routine clears all members of the font map structure and frees all allocated memory back to the system. - */ -void FreeTypeGX::unloadFont() { - if(this->fontData.size() == 0) - return; - - GX_DrawDone(); - GX_Flush(); - - for( std::map::iterator i = this->fontData.begin(); i != this->fontData.end(); i++) { - free(i->second.glyphDataTexture); - } - - this->fontData.clear(); -} - -void FreeTypeGX::changeSize(FT_UInt vPointSize, FT_UInt hPointSize/*=0*/) { - this->unloadFont(); - this->ftPointSize = vPointSize; - FT_Set_Pixel_Sizes(this->ftFace, hPointSize, this->ftPointSize); -} - -/** - * 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); - -} - -/** - * Caches the given font glyph in the instance font texture buffer. - * - * This routine renders and stores the requested glyph's bitmap and relevant information into its own quickly addressible - * structure within an instance-specific map. - * - * @param charCode The requested glyph's character code. - * @return A pointer to the allocated font structure. - */ -ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode) { - 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(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); - - this->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, &this->fontData[charCode]); - - return &this->fontData[charCode]; - } - } - - return NULL; -} - -/** - * Locates each character in this wrapper's configured font face and proccess them. - * - * This routine locates each character in the configured font face and renders the glyph's bitmap. - * Each bitmap and relevant information is loaded into its own quickly addressible structure within an instance-specific map. - */ -uint16_t FreeTypeGX::cacheGlyphDataComplete() { - uint16_t i = 0; - FT_UInt gIndex; - FT_ULong charCode = FT_Get_First_Char( this->ftFace, &gIndex ); - while ( gIndex != 0 ) { - - if(this->cacheGlyphData(charCode) != NULL) { - i++; - } - - charCode = FT_Get_Next_Char( this->ftFace, charCode, &gIndex ); - } - - return i; -} - -/** - * Loads the rendered bitmap into the relevant structure's data buffer. - * - * This routine does a simple byte-wise copy of the glyph's rendered 8-bit grayscale bitmap into the structure's buffer. - * Each byte is converted from the bitmap's intensity value into the a uint32_t RGBA value. - * - * @param bmp A pointer to the most recently rendered glyph's bitmap. - * @param charData A pointer to an allocated ftgxCharData structure whose data represent that of the last rendered glyph. - */ -void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData) { - - uint32_t *glyphData = (uint32_t *)memalign(32, charData->textureWidth * charData->textureHeight * 4); - memset(glyphData, 0x00, charData->textureWidth * charData->textureHeight * 4); - - 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; - } - } - - 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; - } - - free(glyphData); -} - -/** - * Determines the x offset of the rendered string. - * - * This routine calculates the x offset of the rendered string based off of a supplied positional format parameter. - * - * @param width Current pixel width of the string. - * @param format Positional format of the string. - */ -int16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format) { - - if (format & FTGX_JUSTIFY_LEFT ) { - return 0; - } - else if (format & FTGX_JUSTIFY_CENTER ) { - return -(width >> 1); - } - else if (format & FTGX_JUSTIFY_RIGHT ) { - return -width; - } - - return 0; -} - -/** - * Determines the y offset of the rendered string. - * - * This routine calculates the y offset of the rendered string based off of a supplied positional format parameter. - * - * @param offset Current pixel offset data of the string. - * @param format Positional format of the string. - */ -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: - return 0; - - case FTGX_ALIGN_GLYPH_TOP: - return offset->max; - - case FTGX_ALIGN_GLYPH_MIDDLE: - return (offset->max + offset->min + 1) >> 1; - - case FTGX_ALIGN_GLYPH_BOTTOM: - return offset->min; - } - - return 0; -} - -/** - * Processes the supplied text string and prints the results at the specified coordinates. - * - * This routine processes each character of the supplied text string, loads the relevant preprocessed bitmap buffer, - * a texture from said buffer, and loads the resultant texture into the EFB. - * - * @param x Screen X coordinate at which to output the text. - * @param y Screen Y coordinate at which to output the text. Note that this value corresponds to the text string origin and not the top or bottom of the glyphs. - * @param text NULL terminated string to output. - * @param color Optional color to apply to the text characters. If not specified default value is ftgxWhite: (GXColor){0xff, 0xff, 0xff, 0xff} - * @param textStyle Flags which specify any styling which should be applied to the rendered string. - * @return The number of characters printed. - */ -uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, 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; - - 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); - } - - for (uint16_t i = 0; i < strLength; i++) { - - ftgxCharData* glyphData = NULL; - if( this->fontData.find(text[i]) != this->fontData.end() ) { - glyphData = &this->fontData[text[i]]; - } - else { - glyphData = this->cacheGlyphData(text[i]); - } - - if(glyphData != NULL) { - - if(this->ftKerningEnabled && i) { - FT_Get_Kerning( this->ftFace, this->fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta ); - x_pos += pairDelta.x >> 6; - } - - 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); - - x_pos += glyphData->glyphAdvanceX; - printed++; - } - } - - if(textStyle & FTGX_STYLE_MASK) { - this->drawTextFeature(x + x_offset, y + y_offset, this->getWidth(text), this->getOffset(text, &offset), textStyle, color); - } - - return printed; -} - -/** - * \overload - */ -uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, wchar_t const *text, GXColor color, uint16_t textStyle) { - return this->drawText(x, y, (wchar_t *)text, color, textStyle); -} - -void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color) { - uint16_t featureHeight = this->ftPointSize >> 4 > 0 ? this->ftPointSize >> 4 : 1; - - 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; - } - } -} - -/** - * Processes the supplied string and return the width of the string in pixels. - * - * This routine processes each character of the supplied text string and calculates the width of the entire string. - * Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function. - * - * @param text NULL terminated string to calculate. - * @return The width of the text string in pixels. - */ -uint16_t FreeTypeGX::getWidth(wchar_t *text) { - uint16_t strLength = wcslen(text); - uint16_t strWidth = 0; - FT_Vector pairDelta; - - for (uint16_t i = 0; i < strLength; i++) { - - ftgxCharData* glyphData = NULL; - if( this->fontData.find(text[i]) != this->fontData.end() ) { - glyphData = &this->fontData[text[i]]; - } - else { - glyphData = this->cacheGlyphData(text[i]); - } - - if(glyphData != NULL) { - if(this->ftKerningEnabled && (i > 0)) { - FT_Get_Kerning( this->ftFace, this->fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta ); - strWidth += pairDelta.x >> 6; - } - - strWidth += glyphData->glyphAdvanceX; - } - } - - return strWidth; -} - -/** - * - * \overload - */ -uint16_t FreeTypeGX::getWidth(wchar_t const *text) { - return this->getWidth((wchar_t *)text); -} - -/** - * Processes the supplied string and return the height of the string in pixels. - * - * This routine processes each character of the supplied text string and calculates the height of the entire string. - * Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function. - * - * @param text NULL terminated string to calculate. - * @return The height of the text string in pixels. - */ -uint16_t FreeTypeGX::getHeight(wchar_t *text) { - ftgxDataOffset offset; - this->getOffset(text, &offset); - - return offset.max - offset.min; -} - -/** - * - * \overload - */ -uint16_t FreeTypeGX::getHeight(wchar_t const *text) { - return this->getHeight((wchar_t *)text); -} - -/** - * Get the maximum offset above and minimum offset below the font origin line. - * - * This function calculates the maximum pixel height above the font origin line and the minimum - * pixel height below the font origin line and returns the values in an addressible structure. - * - * @param text NULL terminated string to calculate. - * @param offset returns the max and min values above and below the font origin line - * - */ -ftgxDataOffset* FreeTypeGX::getOffset(wchar_t *text, ftgxDataOffset* offset) { - uint16_t strLength = wcslen(text); - int16_t strMax = 0, strMin = 9999; - - for (uint16_t i = 0; i < strLength; i++) { - - ftgxCharData* glyphData = NULL; - if( this->fontData.find(text[i]) != this->fontData.end() ) { - glyphData = &this->fontData[text[i]]; - } - else { - glyphData = this->cacheGlyphData(text[i]); - } - - 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; -} - -/** - * - * \overload - */ -ftgxDataOffset* FreeTypeGX::getOffset(wchar_t const *text, ftgxDataOffset* offset) { - return this->getOffset(text, offset); -} - -/** - * Copies the supplied texture quad to the EFB. - * - * This routine uses the in-built GX quad builder functions to define the texture bounds and location on the EFB target. - * - * @param texObj A pointer to the glyph's initialized texture object. - * @param texWidth The pixel width of the texture object. - * @param texHeight The pixel height of the texture object. - * @param screenX The screen X coordinate at which to output the rendered texture. - * @param screenY The screen Y coordinate at which to output the rendered texture. - * @param color Color to apply to the texture. - */ -void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, GXColor color) { - - GX_LoadTexObj(texObj, GX_TEXMAP0); - GX_InvalidateTexAll(); - - GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); - GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT); - - 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_Position2s16(texWidth + screenX, screenY); - GX_Color4u8(color.r, color.g, color.b, color.a); - GX_TexCoord2f32(1.0f, 0.0f); - - GX_Position2s16(texWidth + screenX, texHeight + screenY); - GX_Color4u8(color.r, color.g, color.b, color.a); - GX_TexCoord2f32(1.0f, 1.0f); - - 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(); -} - -/** - * Creates a feature quad to the EFB. - * - * This function creates a simple quad for displaying underline or strikeout text styling. - * - * @param featureWidth The pixel width of the quad. - * @param featureHeight The pixel height of the quad. - * @param screenX The screen X coordinate at which to output the quad. - * @param screenY The screen Y coordinate at which to output the quad. - * @param color Color to apply to the texture. - */ -void FreeTypeGX::copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, GXColor color) { - - GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR); - GX_SetVtxDesc (GX_VA_TEX0, GX_NONE); - - GX_Begin(GX_QUADS, this->vertexIndex, 4); - GX_Position2s16(screenX, screenY); - 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_Position2s16(featureWidth + screenX, featureHeight + screenY); - GX_Color4u8(color.r, color.g, color.b, color.a); - - GX_Position2s16(screenX, featureHeight + screenY); - GX_Color4u8(color.r, color.g, color.b, color.a); - GX_End(); - - this->setDefaultMode(); -} + + + return strWChar; +} + +/** + * + * \overload + */ +wchar_t* FreeTypeGX::charToWideChar(const char* strChar) { + return FreeTypeGX::charToWideChar((char*) strChar); +} + +/** + * Setup the vertex attribute formats for the glyph textures. + * + * This function sets up the vertex format for the glyph texture on the specified vertex format index. + * Note that this function should not need to be called except if the vertex formats are cleared or the specified + * vertex format index is modified. + * + * @param vertexIndex Vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file. +*/ +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); +} + +/** + * 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 fontBuffer A pointer in memory to a precompiled true type font buffer. + * @param bufferSize Size of the true type font buffer in bytes. + * @param pointSize The desired point size this wrapper's configured font face. + * @param cacheAll Optional flag to specify if all font characters should be cached when the class object is created. If specified as false the characters only become cached the first time they are used. If not specified default value is false. + */ +uint16_t FreeTypeGX::loadFont(uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll) { + this->unloadFont(); + this->ftPointSize = pointSize; + + FT_New_Memory_Face(this->ftLibrary, (FT_Byte *)fontBuffer, bufferSize, 0, &this->ftFace); + + if(this->ftPointSize > 0) + FT_Set_Pixel_Sizes(this->ftFace, 0, this->ftPointSize); + + this->ftSlot = this->ftFace->glyph; + this->ftKerningEnabled = FT_HAS_KERNING(this->ftFace); + + if (cacheAll) { + return this->cacheGlyphDataComplete(); + } + + return 0; +} + +/** + * + * \overload + */ +uint16_t FreeTypeGX::loadFont(const uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll) { + return this->loadFont((uint8_t *)fontBuffer, bufferSize, pointSize, cacheAll); +} + +/** + * Clears all loaded font glyph data. + * + * This routine clears all members of the font map structure and frees all allocated memory back to the system. + */ +void FreeTypeGX::unloadFont() { + if(this->fontData.size() == 0) + return; + + GX_DrawDone(); + GX_Flush(); + + for( std::map::iterator i = this->fontData.begin(); i != this->fontData.end(); i++) { + free(i->second.glyphDataTexture); + } + + this->fontData.clear(); +} + +void FreeTypeGX::changeSize(FT_UInt vPointSize, FT_UInt hPointSize/*=0*/) { + this->unloadFont(); + this->ftPointSize = vPointSize; + FT_Set_Pixel_Sizes(this->ftFace, hPointSize, this->ftPointSize); +} + +/** + * 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); + +} + +/** + * Caches the given font glyph in the instance font texture buffer. + * + * This routine renders and stores the requested glyph's bitmap and relevant information into its own quickly addressible + * structure within an instance-specific map. + * + * @param charCode The requested glyph's character code. + * @return A pointer to the allocated font structure. + */ +ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode) { + 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(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); + + this->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, &this->fontData[charCode]); + + return &this->fontData[charCode]; + } + } + + return NULL; +} + +/** + * Locates each character in this wrapper's configured font face and proccess them. + * + * This routine locates each character in the configured font face and renders the glyph's bitmap. + * Each bitmap and relevant information is loaded into its own quickly addressible structure within an instance-specific map. + */ +uint16_t FreeTypeGX::cacheGlyphDataComplete() { + uint16_t i = 0; + FT_UInt gIndex; + FT_ULong charCode = FT_Get_First_Char( this->ftFace, &gIndex ); + while ( gIndex != 0 ) { + + if(this->cacheGlyphData(charCode) != NULL) { + i++; + } + + charCode = FT_Get_Next_Char( this->ftFace, charCode, &gIndex ); + } + + return i; +} + +/** + * Loads the rendered bitmap into the relevant structure's data buffer. + * + * This routine does a simple byte-wise copy of the glyph's rendered 8-bit grayscale bitmap into the structure's buffer. + * Each byte is converted from the bitmap's intensity value into the a uint32_t RGBA value. + * + * @param bmp A pointer to the most recently rendered glyph's bitmap. + * @param charData A pointer to an allocated ftgxCharData structure whose data represent that of the last rendered glyph. + */ +void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData) { + + uint32_t *glyphData = (uint32_t *)memalign(32, charData->textureWidth * charData->textureHeight * 4); + memset(glyphData, 0x00, charData->textureWidth * charData->textureHeight * 4); + + 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; + } + } + + 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; + } + + free(glyphData); +} + +/** + * Determines the x offset of the rendered string. + * + * This routine calculates the x offset of the rendered string based off of a supplied positional format parameter. + * + * @param width Current pixel width of the string. + * @param format Positional format of the string. + */ +uint16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format) { + + if (format & FTGX_JUSTIFY_LEFT ) { + return 0; + } + else if (format & FTGX_JUSTIFY_CENTER ) { + return width >> 1; + } + else if (format & FTGX_JUSTIFY_RIGHT ) { + return width; + } + + return 0; +} + +/** + * Determines the y offset of the rendered string. + * + * This routine calculates the y offset of the rendered string based off of a supplied positional format parameter. + * + * @param offset Current pixel offset data of the string. + * @param format Positional format of the string. + */ +uint16_t FreeTypeGX::getStyleOffsetHeight(ftgxDataOffset offset, uint16_t format) { + if (format & FTGX_ALIGN_TOP ) { + return -offset.max; + } + else if (format & FTGX_ALIGN_MIDDLE ) { + return -offset.max; + } + else if (format & FTGX_ALIGN_BOTTOM ) { + return offset.min; + } + + return 0; +} + +/** + * Processes the supplied text string and prints the results at the specified coordinates. + * + * This routine processes each character of the supplied text string, loads the relevant preprocessed bitmap buffer, + * a texture from said buffer, and loads the resultant texture into the EFB. + * + * @param x Screen X coordinate at which to output the text. + * @param y Screen Y coordinate at which to output the text. Note that this value corresponds to the text string origin and not the top or bottom of the glyphs. + * @param text NULL terminated string to output. + * @param color Optional color to apply to the text characters. If not specified default value is ftgxWhite: (GXColor){0xff, 0xff, 0xff, 0xff} + * @param textStyle Flags which specify any styling which should be applied to the rendered string. + * @return The number of characters printed. + */ +uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, 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; + + if(textStyle & 0x000F) { + x_offset = this->getStyleOffsetWidth(this->getWidth(text), textStyle); + } + if(textStyle & 0x00F0) { + y_offset = this->getStyleOffsetHeight(this->getOffset(text), textStyle); + } + + for (uint16_t i = 0; i < strLength; i++) { + + ftgxCharData* glyphData = NULL; + if( this->fontData.find(text[i]) != this->fontData.end() ) { + glyphData = &this->fontData[text[i]]; + } + else { + glyphData = this->cacheGlyphData(text[i]); + } + + if(glyphData != NULL) { + + if(this->ftKerningEnabled && i) { + FT_Get_Kerning( this->ftFace, this->fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta ); + x_pos += pairDelta.x >> 6; + } + + 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); + + x_pos += glyphData->glyphAdvanceX; + printed++; + } + } + + if(textStyle & 0x0F00) { + this->drawTextFeature(x - x_offset, y, this->getWidth(text), this->getOffset(text), textStyle, color); + } + + return printed; +} + +/** + * \overload + */ +uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, wchar_t const *text, GXColor color, uint16_t textStyle) { + return this->drawText(x, y, (wchar_t *)text, color, textStyle); +} + +void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, uint16_t width, ftgxDataOffset offsetData, uint16_t format, GXColor color) { + uint16_t featureHeight = this->ftPointSize >> 4 > 0 ? this->ftPointSize >> 4 : 1; + + if (format & FTGX_STYLE_UNDERLINE ) { + switch(format & 0x00F0) { + 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 & 0x00F0) { + case FTGX_ALIGN_TOP: + this->copyFeatureToFramebuffer(width, featureHeight, x, y + ((offsetData.max + offsetData.min) >> 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); + break; + } + } +} + +/** + * Processes the supplied string and return the width of the string in pixels. + * + * This routine processes each character of the supplied text string and calculates the width of the entire string. + * Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function. + * + * @param text NULL terminated string to calculate. + * @return The width of the text string in pixels. + */ +uint16_t FreeTypeGX::getWidth(wchar_t *text) { + uint16_t strLength = wcslen(text); + uint16_t strWidth = 0; + FT_Vector pairDelta; + + for (uint16_t i = 0; i < strLength; i++) { + + ftgxCharData* glyphData = NULL; + if( this->fontData.find(text[i]) != this->fontData.end() ) { + glyphData = &this->fontData[text[i]]; + } + else { + glyphData = this->cacheGlyphData(text[i]); + } + + if(glyphData != NULL) { + if(this->ftKerningEnabled && (i > 0)) { + FT_Get_Kerning( this->ftFace, this->fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta ); + strWidth += pairDelta.x >> 6; + } + + strWidth += glyphData->glyphAdvanceX; + } + } + + return strWidth; +} + +/** + * + * \overload + */ +uint16_t FreeTypeGX::getWidth(wchar_t const *text) { + return this->getWidth((wchar_t *)text); +} + +/** + * Processes the supplied string and return the height of the string in pixels. + * + * This routine processes each character of the supplied text string and calculates the height of the entire string. + * Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function. + * + * @param text NULL terminated string to calculate. + * @return The height of the text string in pixels. + */ +uint16_t FreeTypeGX::getHeight(wchar_t *text) { + ftgxDataOffset offset = this->getOffset(text); + + return offset.max + offset.min; +} + +/** + * + * \overload + */ +uint16_t FreeTypeGX::getHeight(wchar_t const *text) { + return this->getHeight((wchar_t *)text); +} + +/** + * Get the maximum offset above and minimum offset below the font origin line. + * + * This function calculates the maximum pixel height above the font origin line and the minimum + * pixel height below the font origin line and returns the values in an addressible structure. + * + * @param text NULL terminated string to calculate. + * @return The max and min values above and below the font origin line. + */ +ftgxDataOffset FreeTypeGX::getOffset(wchar_t *text) { + uint16_t strLength = wcslen(text); + int16_t strMax = 0, strMin = 0; + + for (uint16_t i = 0; i < strLength; i++) { + + ftgxCharData* glyphData = NULL; + if( this->fontData.find(text[i]) != this->fontData.end() ) { + glyphData = &this->fontData[text[i]]; + } + else { + glyphData = this->cacheGlyphData(text[i]); + } + + if(glyphData != NULL) { + strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax; + strMin = glyphData->renderOffsetMin > strMin ? glyphData->renderOffsetMin : strMin; + } + } + + return (ftgxDataOffset){strMax, strMin}; +} + +/** + * + * \overload + */ +ftgxDataOffset FreeTypeGX::getOffset(wchar_t const *text) { + return this->getOffset(text); +} + +/** + * Copies the supplied texture quad to the EFB. + * + * This routine uses the in-built GX quad builder functions to define the texture bounds and location on the EFB target. + * + * @param texObj A pointer to the glyph's initialized texture object. + * @param texWidth The pixel width of the texture object. + * @param texHeight The pixel height of the texture object. + * @param screenX The screen X coordinate at which to output the rendered texture. + * @param screenY The screen Y coordinate at which to output the rendered texture. + * @param color Color to apply to the texture. + */ +void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, GXColor color) { + + GX_LoadTexObj(texObj, GX_TEXMAP0); + GX_InvalidateTexAll(); + + GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); + GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT); + + 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_Position2s16(texWidth + screenX, screenY); + GX_Color4u8(color.r, color.g, color.b, color.a); + GX_TexCoord2f32(1.0f, 0.0f); + + GX_Position2s16(texWidth + screenX, texHeight + screenY); + GX_Color4u8(color.r, color.g, color.b, color.a); + GX_TexCoord2f32(1.0f, 1.0f); + + 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(); +} + +/** + * Creates a feature quad to the EFB. + * + * This function creates a simple quad for displaying underline or strikeout text styling. + * + * @param featureWidth The pixel width of the quad. + * @param featureHeight The pixel height of the quad. + * @param screenX The screen X coordinate at which to output the quad. + * @param screenY The screen Y coordinate at which to output the quad. + * @param color Color to apply to the texture. + */ +void FreeTypeGX::copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, GXColor color) { + + GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR); + GX_SetVtxDesc (GX_VA_TEX0, GX_NONE); + + GX_Begin(GX_QUADS, this->vertexIndex, 4); + GX_Position2s16(screenX, screenY); + 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_Position2s16(featureWidth + screenX, featureHeight + screenY); + GX_Color4u8(color.r, color.g, color.b, color.a); + + GX_Position2s16(screenX, featureHeight + screenY); + GX_Color4u8(color.r, color.g, color.b, color.a); + GX_End(); + + this->setDefaultMode(); +} diff --git a/source/FreeTypeGX.h b/source/FreeTypeGX.h index 1b86bbd6..2e0e3afe 100644 --- a/source/FreeTypeGX.h +++ b/source/FreeTypeGX.h @@ -1,272 +1,288 @@ -/* - * 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 - * - * This file is part of FreeTypeGX. - * - * FreeTypeGX is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * FreeTypeGX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with FreeTypeGX. If not, see . - */ - -/** \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_ - -#include -#include -#include FT_FREETYPE_H -#include FT_BITMAP_H -#include - -#include -#include -#include - -/*! forward deklaration of private structures - * - */ -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_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_STYLE_UNDERLINE 0x0100 -#define FTGX_STYLE_STRIKE 0x0200 -#define FTGX_STYLE_MASK 0x0f00 - -#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 - -#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. */ - -/*! \class FreeTypeGX - * \brief Wrapper class for the libFreeType library with GX rendering. - * \author Armin Tamzarian - * \version 0.2.4 - * - * FreeTypeGX acts as a wrapper class for the libFreeType library. It supports precaching of transformed glyph data into - * 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. - */ -class FreeTypeGX { - - private: - FT_Library ftLibrary; /**< FreeType FT_Library instance. */ - FT_Face ftFace; /**< FreeType reusable FT_Face typographic object. */ - FT_GlyphSlot ftSlot; /**< FreeType reusable FT_GlyphSlot glyph container object. */ - FT_UInt ftPointSize; /**< Requested size of the rendered font. */ - bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */ - - 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. */ - std::map fontData; /**< Map which holds the glyph data structures for the corresponding characters. */ - - static uint16_t adjustTextureWidth(uint16_t textureWidth, uint8_t textureFormat); - static uint16_t adjustTextureHeight(uint16_t textureHeight, uint8_t textureFormat); - - static int16_t getStyleOffsetWidth(uint16_t width, uint16_t format); - static int16_t getStyleOffsetHeight(ftgxDataOffset *offset, uint16_t format); - - void unloadFont(); - ftgxCharData *cacheGlyphData(wchar_t charCode); - uint16_t cacheGlyphDataComplete(); - void loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData); - - void setDefaultMode(); - - 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); - - public: - FreeTypeGX(uint8_t textureFormat = GX_TF_RGBA8, uint8_t vertexIndex = GX_VTXFMT1); - ~FreeTypeGX(); - - static wchar_t* charToWideChar(char* p); - static wchar_t* charToWideChar(const char* p); - void setVertexFormat(uint8_t vertexIndex); - void setCompatibilityMode(uint32_t compatibilityMode); - - uint16_t loadFont(uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll = false); - uint16_t loadFont(const uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll = false); - void changeSize(FT_UInt vPointSize, FT_UInt hPointSize=0); - - uint16_t drawText(int16_t x, int16_t y, wchar_t *text, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL); - uint16_t drawText(int16_t x, int16_t y, wchar_t const *text, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL); - - uint16_t getWidth(wchar_t *text); - uint16_t getWidth(wchar_t const *text); - uint16_t getHeight(wchar_t *text); - uint16_t getHeight(wchar_t const *text); - ftgxDataOffset* getOffset(wchar_t *text, ftgxDataOffset* offset); - ftgxDataOffset* getOffset(wchar_t const *text, ftgxDataOffset* offset); -}; - -#endif /* FREETYPEGX_H_ */ +/* + * 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 + * + * This file is part of FreeTypeGX. + * + * FreeTypeGX is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FreeTypeGX is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FreeTypeGX. If not, see . + */ + + +/** \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_ + +#include +#include +#include FT_FREETYPE_H +#include FT_BITMAP_H +#include + +#include +#include +#include + +/*! \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 max; /**< Maximum data offset. */ + int16_t min; /**< Minimum data offset. */ +} 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 0x0004 + +#define FTGX_ALIGN_TOP 0x0010 +#define FTGX_ALIGN_MIDDLE 0x0020 +#define FTGX_ALIGN_BOTTOM 0x0040 + +#define FTGX_STYLE_UNDERLINE 0x0100 +#define FTGX_STYLE_STRIKE 0x0200 + +#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 + +#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. */ + +/*! \class FreeTypeGX + * \brief Wrapper class for the libFreeType library with GX rendering. + * \author Armin Tamzarian + * \version 0.2.4 + * + * FreeTypeGX acts as a wrapper class for the libFreeType library. It supports precaching of transformed glyph data into + * 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. + */ +class FreeTypeGX { + + private: + FT_Library ftLibrary; /**< FreeType FT_Library instance. */ + FT_Face ftFace; /**< FreeType reusable FT_Face typographic object. */ + FT_GlyphSlot ftSlot; /**< FreeType reusable FT_GlyphSlot glyph container object. */ + FT_UInt ftPointSize; /**< Requested size of the rendered font. */ + bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */ + + 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. */ + std::map fontData; /**< Map which holds the glyph data structures for the corresponding characters. */ + + static uint16_t adjustTextureWidth(uint16_t textureWidth, uint8_t textureFormat); + static uint16_t adjustTextureHeight(uint16_t textureHeight, uint8_t textureFormat); + + static uint16_t getStyleOffsetWidth(uint16_t width, uint16_t format); + static uint16_t getStyleOffsetHeight(ftgxDataOffset offset, uint16_t format); + + void unloadFont(); + ftgxCharData *cacheGlyphData(wchar_t charCode); + uint16_t cacheGlyphDataComplete(); + void loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData); + + void setDefaultMode(); + + 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); + + public: + FreeTypeGX(uint8_t textureFormat = GX_TF_RGBA8, uint8_t vertexIndex = GX_VTXFMT1); + ~FreeTypeGX(); + + static wchar_t* charToWideChar(char* p); + static wchar_t* charToWideChar(const char* p); + void setVertexFormat(uint8_t vertexIndex); + void setCompatibilityMode(uint32_t compatibilityMode); + + uint16_t loadFont(uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll = false); + uint16_t loadFont(const uint8_t* fontBuffer, FT_Long bufferSize, FT_UInt pointSize, bool cacheAll = false); + void changeSize(FT_UInt vPointSize, FT_UInt hPointSize=0); + + uint16_t drawText(int16_t x, int16_t y, wchar_t *text, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL); + uint16_t drawText(int16_t x, int16_t y, wchar_t const *text, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL); + + uint16_t getWidth(wchar_t *text); + uint16_t getWidth(wchar_t const *text); + uint16_t getHeight(wchar_t *text); + uint16_t getHeight(wchar_t const *text); + ftgxDataOffset getOffset(wchar_t *text); + ftgxDataOffset getOffset(wchar_t const *text); +}; + +#endif /* FREETYPEGX_H_ */ diff --git a/source/cfg.c b/source/cfg.c index c0db7bfb..03383293 100644 --- a/source/cfg.c +++ b/source/cfg.c @@ -244,6 +244,7 @@ void CFG_Default(int widescreen) // -1 = non forced Mode snprintf(CFG.unlockCode, sizeof(CFG.unlockCode), "ab121b"); // default password snprintf(CFG.language_path, sizeof(CFG.language_path), "SD:/config/language/"); snprintf(CFG.oggload_path, sizeof(CFG.oggload_path), "SD:/config/backgroundmusic/"); + snprintf(CFG.update_path, sizeof(CFG.update_path), "SD:/apps/usbloader_gx/"); sprintf(CFG.ogg_path, "notset"); CFG.parentalcontrol = 0; @@ -494,6 +495,10 @@ void cfg_set(char *name, char *val) strcopy(CFG.language_path, val, sizeof(CFG.language_path)); return; } + if (strcmp(name, "update_path") == 0) { + strcopy(CFG.update_path, val, sizeof(CFG.update_path)); + return; + } if (strcmp(name, "oggload_path") == 0) { strcopy(CFG.oggload_path, val, sizeof(CFG.oggload_path)); return; @@ -1090,6 +1095,7 @@ bool cfg_save_global()// save global settings fprintf(f, "ogg_path = %s\n ", CFG.ogg_path); fprintf(f, "wiilight = %d\n ", Settings.wiilight); fprintf(f, "gameDisplay = %d\n ", Settings.gameDisplay); + fprintf(f, "update_path = %s\n ", CFG.update_path); fclose(f); return true; } diff --git a/source/cfg.h b/source/cfg.h index 907a1f54..3f32f835 100644 --- a/source/cfg.h +++ b/source/cfg.h @@ -72,6 +72,7 @@ struct CFG char language_path[100]; char oggload_path[100]; char ogg_path[150]; + char update_path[150]; short keyset; }; diff --git a/source/fatmounter.c b/source/fatmounter.c index 5bf7769b..8e3fa841 100644 --- a/source/fatmounter.c +++ b/source/fatmounter.c @@ -51,7 +51,7 @@ return -1; void SDCard_deInit() { //First unmount all the devs... - fatUnmount("SD"); + fatUnmount("SD:/"); //...and then shutdown em! __io_wiisd.shutdown(); } diff --git a/source/filelist.h b/source/filelist.h index b5e972ba..81d09ee0 100644 --- a/source/filelist.h +++ b/source/filelist.h @@ -287,4 +287,7 @@ extern const u32 arrangeList_gray_png_size; extern const u8 arrangeCarosselle_gray_png[]; extern const u32 arrangeCarosselle_gray_png_size; +extern const u8 updateRev_png[]; +extern const u32 updateRev_png_size; + #endif diff --git a/source/http.c b/source/http.c index c187e1af..864e6a71 100644 --- a/source/http.c +++ b/source/http.c @@ -231,4 +231,15 @@ struct block downloadfile(const char *url) free(response.data); return file; +} + +s32 GetConnection(char * domain) { + + u32 ipaddress = getipbynamecached(domain); + if(ipaddress == 0) { + return -1; + } + s32 connection = server_connect(ipaddress, 80); + return connection; + } diff --git a/source/http.h b/source/http.h index 0698f0ce..50fccb49 100644 --- a/source/http.h +++ b/source/http.h @@ -19,7 +19,7 @@ extern "C" #include "dns.h" /** - * A simple structure to keep track of the size of a malloc()ated block of memory + * A simple structure to keep track of the size of a malloc()ated block of memory */ struct block { @@ -29,7 +29,8 @@ struct block extern const struct block emptyblock; -struct block downloadfile(const char *url); +struct block downloadfile(const char *url); +s32 GetConnection(char * domain); #ifdef __cplusplus } diff --git a/source/images/downloadRev.png b/source/images/updateRev.png similarity index 100% rename from source/images/downloadRev.png rename to source/images/updateRev.png diff --git a/source/language.c b/source/language.c index f9df1f15..9d235ecc 100644 --- a/source/language.c +++ b/source/language.c @@ -74,7 +74,7 @@ snprintf(LANGUAGE.Display, sizeof(LANGUAGE.Display), "Display"); snprintf(LANGUAGE.Doyouwanttoformat, sizeof(LANGUAGE.Doyouwanttoformat), "Do you want to format:"); snprintf(LANGUAGE.Doyoureallywanttodelete, sizeof(LANGUAGE.Doyoureallywanttodelete), "Do you really want to delete:"); snprintf(LANGUAGE.Doyouwanttoretryfor30secs, sizeof(LANGUAGE.Doyouwanttoretryfor30secs), "Do you want to retry for 30 secs?"); -snprintf(LANGUAGE.Downloadingfile, sizeof(LANGUAGE.Downloadingfile), "Downloading file:"); +snprintf(LANGUAGE.Downloadingfile, sizeof(LANGUAGE.Downloadingfile), "Downloading file"); snprintf(LANGUAGE.DownloadBoxartimage, sizeof(LANGUAGE.DownloadBoxartimage), "Download Boxart image?"); snprintf(LANGUAGE.Downloadfinished, sizeof(LANGUAGE.Downloadfinished), "Download finished"); snprintf(LANGUAGE.Defaultgamesettings, sizeof(LANGUAGE.Defaultgamesettings), "Default Gamesettings"); @@ -202,6 +202,9 @@ snprintf(LANGUAGE.Timeleft, sizeof(LANGUAGE.Timeleft), "Time left:"); snprintf(LANGUAGE.Unlock, sizeof(LANGUAGE.Unlock), "Unlock"); snprintf(LANGUAGE.Unicodefix, sizeof(LANGUAGE.Unicodefix), "Unicode Fix"); snprintf(LANGUAGE.Uninstall, sizeof(LANGUAGE.Uninstall), "Uninstall"); +snprintf(LANGUAGE.Updatepath, sizeof(LANGUAGE.Updatepath), "Updatepath"); +snprintf(LANGUAGE.Updatepathchanged, sizeof(LANGUAGE.Updatepathchanged), "Updatepath changed."); +snprintf(LANGUAGE.Updatefailed, sizeof(LANGUAGE.Updatefailed), "Update failed"); snprintf(LANGUAGE.USBLoaderisprotected, sizeof(LANGUAGE.USBLoaderisprotected), "USB Loader GX is protected"); snprintf(LANGUAGE.USBDevicenotfound, sizeof(LANGUAGE.USBDevicenotfound), "USB Device not found"); snprintf(LANGUAGE.VideoMode, sizeof(LANGUAGE.VideoMode), "Video Mode"); @@ -936,6 +939,18 @@ void language_set(char *name, char *val) strcopy(LANGUAGE.Uninstall, val, sizeof(LANGUAGE.Uninstall)); return; } + if (strcmp(name, "Updatepath") == 0) { + strcopy(LANGUAGE.Updatepath, val, sizeof(LANGUAGE.Updatepath)); + return; + } + if (strcmp(name, "Updatepathchanged") == 0) { + strcopy(LANGUAGE.Updatepathchanged, val, sizeof(LANGUAGE.Updatepathchanged)); + return; + } + if (strcmp(name, "Updatefailed") == 0) { + strcopy(LANGUAGE.Updatefailed, val, sizeof(LANGUAGE.Updatefailed)); + return; + } if (strcmp(name, "USBLoaderisprotected") == 0) { strcopy(LANGUAGE.USBLoaderisprotected, val, sizeof(LANGUAGE.USBLoaderisprotected)); return; diff --git a/source/language.h b/source/language.h index 748180fb..fbab8a34 100644 --- a/source/language.h +++ b/source/language.h @@ -188,6 +188,9 @@ struct LANGUAGE char Uninstall[50]; char USBLoaderisprotected[80]; char USBDevicenotfound[80]; + char Updatepath[50]; + char Updatepathchanged[50]; + char Updatefailed[40]; char VideoMode[50]; char VIDTVPatch[50]; char Volume[50]; diff --git a/source/libwiigui/gui.h b/source/libwiigui/gui.h index b5ba4793..93269187 100644 --- a/source/libwiigui/gui.h +++ b/source/libwiigui/gui.h @@ -664,7 +664,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); + 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); @@ -672,12 +672,14 @@ 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); //!Sets the font color //!\param c Font color @@ -685,7 +687,7 @@ class GuiText : public GuiElement //!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/*, u16 m=0xffff*/); //!Sets the text alignment //!\param hor Horizontal alignment (ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTRE) //!\param vert Vertical alignment (ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE) @@ -699,6 +701,12 @@ class GuiText : public GuiElement void SetWidescreen(bool w); //!Constantly called to draw the text void Draw(); + enum { + WRAP, + DOTTED, + SCROLL, + MARQUEE + }; protected: wchar_t* text; //!< Unicode text value int size; //!< Font size diff --git a/source/libwiigui/gui_text.cpp b/source/libwiigui/gui_text.cpp index ce29e1fa..276d6532 100644 --- a/source/libwiigui/gui_text.cpp +++ b/source/libwiigui/gui_text.cpp @@ -13,12 +13,12 @@ static int currentSize = 0; static int currentWidescreen = 0; static int presetSize = 0; -static GXColor presetColor = (GXColor){255, 255, 255, 255}; static int presetMaxWidth = 0; -static int presetWrapMode = 0; -static u16 presetStyle = 0; +static int presetWrapMode = GuiText::WRAP; static int presetAlignmentHor = 0; static int presetAlignmentVert = 0; +static u16 presetStyle = 0; +static GXColor presetColor = (GXColor){255, 255, 255, 255}; /** * Constructor for the GuiText class. @@ -35,14 +35,14 @@ GuiText::GuiText(const char * t, int s, GXColor c) scrollPos1 = 0; scrollPos2 = 0; scrollDelay = 0; - font = fontSystem; + font = NULL; widescreen = 0; //added alignmentHor = ALIGN_CENTRE; alignmentVert = ALIGN_MIDDLE; if(t) - text = FreeTypeGX::charToWideChar((char *)t); + text = fontSystem->charToWideChar((char *)t); } /** @@ -60,14 +60,14 @@ GuiText::GuiText(const char * t) scrollPos1 = 0; scrollPos2 = 0; scrollDelay = 0; - font = fontSystem; + font = NULL; widescreen = 0; //added alignmentHor = presetAlignmentHor; alignmentVert = presetAlignmentVert; if(t) - text = FreeTypeGX::charToWideChar((char *)t); + text = fontSystem->charToWideChar((char *)t); } /** @@ -90,18 +90,17 @@ void GuiText::SetText(const char * t) text = NULL; if(t) - text = FreeTypeGX::charToWideChar((char *)t); + text = fontSystem->charToWideChar((char *)t); scrollPos2 = 0; scrollDelay = 0; } -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; } @@ -126,17 +125,16 @@ void GuiText::SetColor(GXColor c) alpha = c.a; } -void GuiText::SetStyle(u16 s, u16 m/*=0xffff*/) +void GuiText::SetStyle(u16 s) { LOCK(this); - style &= ~m; - style |= s & m; + style = s; } void GuiText::SetAlignment(int hor, int vert) { LOCK(this); - style = FTGX_NULL; + style = 0; switch(hor) { @@ -172,7 +170,7 @@ void GuiText::SetAlignment(int hor, int vert) void GuiText::SetFont(FreeTypeGX *f) { LOCK(this); - font = f ? f : fontSystem; + font = f; } int GuiText::GetTextWidth() @@ -182,12 +180,13 @@ int GuiText::GetTextWidth() if(newSize != currentSize || currentWidescreen != widescreen) { - font->changeSize(newSize, widescreen ? newSize*0.8 : 0); + //fontSystem->changeSize(newSize); + (font ? font : fontSystem)->changeSize(newSize, widescreen ? newSize*0.8 : 0); currentSize = newSize; currentWidescreen = widescreen; } - return font->getWidth(text); -} + return (font ? font : fontSystem)->getWidth(text); +} void GuiText::SetWidescreen(bool w) { @@ -213,17 +212,18 @@ void GuiText::Draw() if(newSize != currentSize || currentWidescreen != widescreen) { - font->changeSize(newSize, widescreen ? newSize*0.8 : 0); + //fontSystem->changeSize(newSize); + (font ? font : fontSystem)->changeSize(newSize, widescreen ? newSize*0.8 : 0); currentSize = newSize; currentWidescreen = widescreen; } int voffset = 0; -// if(alignmentVert == ALIGN_MIDDLE) -// voffset = -newSize/2 + 2; + if(alignmentVert == ALIGN_MIDDLE) + voffset = -newSize/2 + 2; - if(maxWidth > 0 && font->getWidth(text) > maxWidth) + if(maxWidth > 0 && (font ? font : fontSystem)->getWidth(text) > maxWidth) { if(wrapMode == GuiText::WRAP) // text wrapping { @@ -246,7 +246,8 @@ void GuiText::Draw() if(text[ch] == ' ' || ch == strlen-1) { - if(font->getWidth(tmptext[linenum]) >= maxWidth) + if((font ? font : fontSystem)->getWidth(tmptext[linenum]) >= maxWidth) + //if(fontSystem->getWidth(tmptext[linenum]) >= maxWidth) { if(lastSpace >= 0) { @@ -277,7 +278,7 @@ void GuiText::Draw() for(i=0; i < linenum; i++) { - font->drawText(this->GetLeft(), this->GetTop()+voffset+i*lineheight, tmptext[i], c, style); + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop()+voffset+i*lineheight, tmptext[i], c, style); delete tmptext[i]; } } @@ -295,32 +296,31 @@ void GuiText::Draw() save[i] = text[dotPos+i]; text[dotPos+i] = (i != 3 ? _TEXT('.') : 0); } - if((font->getWidth(text)) <= maxWidth) + if(((font ? font : fontSystem)->getWidth(text)) <= maxWidth) { - font->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style); + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style); drawed = true; } - + for(i=0; i<4; i++) // write saved Text back text[dotPos+i] = save[i]; dotPos--; } if(!drawed) - font->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style); + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style); } else if(wrapMode == GuiText::SCROLL) // text scroller { 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->getWidth(text); + int textWidth = (font ? font : fontSystem)->getWidth(text); text[scrollPos2] = save; // restore Pos2 if(textWidth <= maxWidth) break; @@ -329,22 +329,15 @@ void GuiText::Draw() } else if(scrollPos2 > 0 && frameCount >= scrollDelay) { - - if(--scrollOffset < 0) - { - wchar_t tmp[] = { text[scrollPos1], text[scrollPos1+1], 0 }; - scrollOffset += font->getWidth(tmp) - font->getWidth(tmp+1); - scrollPos1++; - } - + scrollPos1++; int strlen = wcslen(text); for(; scrollPos2 < strlen; scrollPos2++) { save = text[scrollPos2+1]; // save Pos2 text[scrollPos2+1] = 0; - int textWidth = font->getWidth(&text[scrollPos1]); + int textWidth = (font ? font : fontSystem)->getWidth(&text[scrollPos1]); text[scrollPos2+1] = save; // restore Pos2 - if(textWidth+scrollOffset > maxWidth) + if(textWidth > maxWidth) break; } if(scrollPos2 == strlen) @@ -353,28 +346,20 @@ void GuiText::Draw() scrollDelay = frameCount+25; // when dir-change wait 25 Frames } else - scrollDelay = frameCount+1; // wait 1 Frames + scrollDelay = frameCount+10; // wait 10 Frames } else if(frameCount >= scrollDelay) { scrollPos2 = -scrollPos2; - - scrollOffset++; - wchar_t tmp[] = { text[scrollPos1-1], text[scrollPos1], 0 }; - int tmpOffset = font->getWidth(tmp) - font->getWidth(tmp+1); - if(scrollOffset >= tmpOffset) - { - scrollOffset -= tmpOffset; - scrollPos1--; - } + scrollPos1--; for(; scrollPos2 > scrollPos1; scrollPos2--) { save = text[scrollPos2]; // save Pos2 text[scrollPos2] = 0; - int textWidth = font->getWidth(&text[scrollPos1]); + int textWidth = (font ? font : fontSystem)->getWidth(&text[scrollPos1]); text[scrollPos2] = save; // restore Pos2 - if(textWidth+scrollOffset <= maxWidth) + if(textWidth <= maxWidth) break; } if(scrollPos1 == 0) @@ -383,34 +368,19 @@ void GuiText::Draw() scrollDelay = frameCount+25; // when dir-change wait 25 Frames } else - scrollDelay = frameCount+1; // wait 10 Frames + scrollDelay = frameCount+10; // wait 10 Frames 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->drawText(drawX, this->GetTop()+voffset, &text[scrollPos1], c, drawStyle); + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop()+voffset, &text[scrollPos1], c, style); text[abs(scrollPos2)] = save; // restore Pos2 - } + } } else { - font->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style); + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style); } this->UpdateEffects(); } diff --git a/source/menu.cpp b/source/menu.cpp index 4193d6d8..117d4a4e 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -42,6 +42,7 @@ #include "libwiigui/gui_diskcover.h" #include "mp3s.h" #include "fatmounter.h" +#include "updater.h" #define MAX_CHARACTERS 38 extern FreeTypeGX *fontClock; //CLOCK @@ -228,7 +229,7 @@ static void WindowCredits(void * ptr) txt[i] = new GuiText(LANGUAGE.OfficialSite, 20, (GXColor){255, 255, 255, 255}); txt[i]->SetAlignment(ALIGN_CENTRE, ALIGN_TOP); txt[i]->SetPosition(-180,y); i++; y+=28; - GuiText::SetPresets(22, (GXColor){255, 255, 255, 255}, 0, GuiText::WRAP, + txt[i]->SetPresets(22, (GXColor){255, 255, 255, 255}, 0, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP, ALIGN_LEFT, ALIGN_TOP); txt[i] = new GuiText("Coding:"); @@ -2173,9 +2174,9 @@ ProgressDownloadWindow(int choice2) if ((Settings.wsprompt == yes) && (CFG.widescreen)){/////////////adjust for widescreen progressbarImg.SetPosition(80,40); progressbarImg.SetTile(80*i/cntMissFiles); + } else { + progressbarImg.SetTile(100*i/cntMissFiles); } - else{ - progressbarImg.SetTile(100*i/cntMissFiles);} sprintf(msg, "%i %s", cntMissFiles - i, LANGUAGE.filesleft); msgTxt.SetText(msg); @@ -2268,6 +2269,315 @@ ProgressDownloadWindow(int choice2) } } +/**************************************************************************** + * ProgressWindow + * + * Opens a window, which displays progress to the user. Can either display a + * progress bar showing % completion, or a throbber that only shows that an + * action is in progress. + ***************************************************************************/ +int +ProgressUpdateWindow() +{ + + int ret = 0, failed = 0; + const unsigned int blocksize = 1024; + char hostip[16]; + char * IP = NULL; + u8 blockbuffer[blocksize] ATTRIBUTE_ALIGN(32); + + GuiWindow promptWindow(472,320); + promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); + promptWindow.SetPosition(0, -10); + + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, vol); + GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, vol); + + char imgPath[100]; + snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); + GuiImageData btnOutline(imgPath, button_dialogue_box_png); + snprintf(imgPath, sizeof(imgPath), "%sdialogue_box.png", CFG.theme_path); + GuiImageData dialogBox(imgPath, dialogue_box_png); + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + GuiImage dialogBoxImg(&dialogBox); + if (Settings.wsprompt == yes){ + dialogBoxImg.SetWidescreen(CFG.widescreen);} + + snprintf(imgPath, sizeof(imgPath), "%sprogressbar_outline.png", CFG.theme_path); + GuiImageData progressbarOutline(imgPath, progressbar_outline_png); + GuiImage progressbarOutlineImg(&progressbarOutline); + if (Settings.wsprompt == yes){ + progressbarOutlineImg.SetWidescreen(CFG.widescreen);} + progressbarOutlineImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + progressbarOutlineImg.SetPosition(25, 7); + + snprintf(imgPath, sizeof(imgPath), "%sprogressbar_empty.png", CFG.theme_path); + GuiImageData progressbarEmpty(imgPath, progressbar_empty_png); + GuiImage progressbarEmptyImg(&progressbarEmpty); + progressbarEmptyImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + progressbarEmptyImg.SetPosition(25, 7); + progressbarEmptyImg.SetTile(100); + + snprintf(imgPath, sizeof(imgPath), "%sprogressbar.png", CFG.theme_path); + GuiImageData progressbar(imgPath, progressbar_png); + progressbarImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + progressbarImg.SetPosition(25, 7); + + char title[50]; + sprintf(title, "%s", "Checking for Updates"); + GuiText titleTxt(title, 26, (GXColor){THEME.prompttxt_r, THEME.prompttxt_g, THEME.prompttxt_b, 255}); //{0, 0, 0, 255}); + titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); + titleTxt.SetPosition(0,50); + char msg[50]; + sprintf(msg, "%s", LANGUAGE.InitializingNetwork); + GuiText msgTxt(msg, 26, (GXColor){THEME.prompttxt_r, THEME.prompttxt_g, THEME.prompttxt_b, 255}); //{0, 0, 0, 255}); + msgTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); + msgTxt.SetPosition(0,140); + char msg2[50] = " "; + GuiText msg2Txt(msg2, 26, (GXColor){THEME.prompttxt_r, THEME.prompttxt_g, THEME.prompttxt_b, 255}); //{0, 0, 0, 255}); + msg2Txt.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); + msg2Txt.SetPosition(0, 50); + + prTxt.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); + prTxt.SetPosition(0, 7); + + GuiText btn1Txt(LANGUAGE.Cancel, 22, (GXColor){THEME.prompttxt_r, THEME.prompttxt_g, THEME.prompttxt_b, 255}); //{0, 0, 0, 255}); + GuiImage btn1Img(&btnOutline); + if (Settings.wsprompt == yes){ + btn1Txt.SetWidescreen(CFG.widescreen); + btn1Img.SetWidescreen(CFG.widescreen);} + GuiButton btn1(btnOutline.GetWidth(), btnOutline.GetHeight()); + btn1.SetAlignment(ALIGN_CENTRE, ALIGN_BOTTOM); + btn1.SetPosition(0, -40); + btn1.SetLabel(&btn1Txt); + btn1.SetImage(&btn1Img); + btn1.SetSoundOver(&btnSoundOver); + btn1.SetSoundClick(&btnClick); + btn1.SetTrigger(&trigA); + btn1.SetState(STATE_SELECTED); + btn1.SetEffectGrow(); + + if ((Settings.wsprompt == yes) && (CFG.widescreen)){/////////////adjust for widescreen + progressbarOutlineImg.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); + progressbarOutlineImg.SetPosition(0, 7); + progressbarEmptyImg.SetPosition(80,7); + progressbarEmptyImg.SetTile(78); + progressbarImg.SetPosition(80, 7); + } + + promptWindow.Append(&dialogBoxImg); + promptWindow.Append(&titleTxt); + promptWindow.Append(&msgTxt); + promptWindow.Append(&msg2Txt); + promptWindow.Append(&btn1); + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&promptWindow); + mainWindow->ChangeFocus(&promptWindow); + ResumeGui(); + + struct stat st; + if(stat(CFG.update_path, &st) != 0) { + char dir[100]; + snprintf(dir,strlen(CFG.update_path),"%s",CFG.update_path); + if (mkdir(dir, 0777) == -1) { + if(subfoldercheck(dir) != 1) { + WindowPrompt(LANGUAGE.Error,LANGUAGE.Cantcreatedirectory,LANGUAGE.ok,0,0,0); + ret = -1; + failed = -1; + } + } + } + + char dolpath[150]; + char dolpathsuccess[150]; + snprintf(dolpath, sizeof(dolpath), "%sbootnew.dol", CFG.update_path); + snprintf(dolpathsuccess, sizeof(dolpathsuccess), "%sboot.dol", CFG.update_path); + + while (!IP && !(ret < 0)) { + + VIDEO_WaitVSync(); + + ret = Net_Init(hostip); + + if (ret > 0) { + IP = hostip; + msgTxt.SetText(IP); + } + + if (ret <= 0) { + msgTxt.SetText(LANGUAGE.Couldnotinitializenetwork); + } + + if(btn1.GetState() == STATE_CLICKED) { + IP = 0; + ret = -1; + failed = -1; + btn1.ResetState(); + break; + } + } + + if(IP && ret >= 0) { + + networkisinitialized = 1; + + int revnumber = 0; + int currentrev = atoi(SVN_REV); + + SDCard_deInit(); + struct block file = downloadfile("http://www.techjawa.com/usbloadergx/rev.txt"); + FILE *pfile; + SDCard_Init(); + + if(file.data != NULL) + { + char revtxt[10]; + pfile = fopen("SD:/rev.txt", "w"); + fwrite(file.data,1,file.size,pfile); + fclose(pfile); + //has to be repeated or it isnt working (first file download bug) + pfile = fopen("SD:/rev.txt", "w"); + fwrite(file.data,1,file.size,pfile); + fclose(pfile); + //"w+" doesnt work, needs to be reopened as "r" + pfile = fopen("SD:/rev.txt", "r"); + int c = 0, i = 0; + while(c != EOF || i < 10) { + c = fgetc(pfile); + if (c != EOF) { + revtxt[i] = c; + } else { + revtxt[i] = 0x00; + break; + } + i++; + } + fclose(pfile); + revnumber = atoi(revtxt); + remove("SD:/rev.txt"); + free(file.data); + } + + if(revnumber > currentrev) { + sprintf(msg, "Rev%i available.", revnumber); + int choice = WindowPrompt(msg, "Do you want to update?", LANGUAGE.Yes, LANGUAGE.No, 0, 0); + if(choice == 1) { + sprintf(title, "%s", "Updating USB Loader GX"); + titleTxt.SetText(title); + msgTxt.SetPosition(0,100); + promptWindow.Append(&progressbarEmptyImg); + promptWindow.Append(&progressbarImg); + promptWindow.Append(&progressbarOutlineImg); + promptWindow.Append(&prTxt); + sprintf(msg, "Updating to Rev%i", revnumber); + msgTxt.SetText(msg); + int filesize = downloadrev("http://www.techjawa.com/usbloadergx/boot.dol"); + if(filesize > 0) { + pfile = fopen(dolpath, "wb"); + for (int i = 0; i < filesize; i += blocksize) { + sprintf(prozent, "%i%%", 100*i/filesize); + prTxt.SetText(prozent); + if ((Settings.wsprompt == yes) && (CFG.widescreen)){/////////////adjust for widescreen + progressbarImg.SetTile(80*i/filesize); + } else { + progressbarImg.SetTile(100*i/filesize); + } + sprintf(msg2, "%iKB/%iKB", i/1024, filesize/1024); + msg2Txt.SetText(msg2); + + if(btn1.GetState() == STATE_CLICKED) { + fclose(pfile); + remove(dolpath); + failed = -1; + btn1.ResetState(); + break; + } + + u32 blksize; + blksize = (u32)(filesize - i); + if (blksize > blocksize) + blksize = blocksize; + + ret = network_read(blockbuffer, blksize); + if ((u32)ret != blksize) { + failed = -1; + ret = -1; + fclose(pfile); + remove(dolpath); + break; + } + fwrite(blockbuffer,1,blksize, pfile); + } + fclose(pfile); + if(!failed) { + //remove old + if(checkfile(dolpathsuccess)){ + remove(dolpathsuccess); + } + //rename new to old + rename(dolpath, dolpathsuccess); + + //get the icon.png and the meta.xml + char xmliconpath[150]; + file = downloadfile("http://www.techjawa.com/usbloadergx/meta.file"); + if(file.data != NULL){ + sprintf(xmliconpath, "%smeta.xml", CFG.update_path); + pfile = fopen(xmliconpath, "wb"); + fwrite(file.data,1,file.size,pfile); + fclose(pfile); + free(file.data); + } + file = downloadfile("http://www.techjawa.com/usbloadergx/icon.png"); + if(file.data != NULL){ + sprintf(xmliconpath, "%sicon.png", CFG.update_path); + pfile = fopen(xmliconpath, "wb"); + fwrite(file.data,1,file.size,pfile); + fclose(pfile); + free(file.data); + } + } + } else { + failed = -1; + } + } else { + ret = -1; + } + + } else { + WindowPrompt("No new updates", 0, "OK", 0, 0, 0); + ret = -1; + } + + } + + CloseConnection(); + + if(!failed && ret >= 0) { + WindowPrompt("Successfully updated ", "Restarting the Loader", "OK", 0, 0, 0); + if (*((u32*) 0x80001800)) exit(0); + SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); + } + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while(promptWindow.GetEffect() > 0) usleep(50); + + HaltGui(); + mainWindow->Remove(&promptWindow); + mainWindow->SetState(STATE_DEFAULT); + ResumeGui(); + + if(failed != 0) + return failed; + + return 1; +} + /**************************************************************************** * UpdateGUI @@ -4140,7 +4450,6 @@ static int MenuSettings() char imgPath[100]; - snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); GuiImageData btnOutline(imgPath, button_dialogue_box_png); snprintf(imgPath, sizeof(imgPath), "%ssettings_background.png", CFG.theme_path); @@ -4151,6 +4460,8 @@ static int MenuSettings() GuiImageData tab2(imgPath, tab_bg2_png); snprintf(imgPath, sizeof(imgPath), "%stab_bg3.png", CFG.theme_path); GuiImageData tab3(imgPath, tab_bg3_png); + snprintf(imgPath, sizeof(imgPath), "%supdateRev.png", CFG.theme_path); + GuiImageData updateRevImgData(imgPath, updateRev_png); GuiTrigger trigA; trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); @@ -4249,6 +4560,19 @@ static int MenuSettings() lockBtn.SetTrigger(&trigA); lockBtn.SetEffectGrow(); + GuiImage updateBtnImg(&updateRevImgData); + updateBtnImg.SetWidescreen(CFG.widescreen); + GuiButton updateBtn(updateBtnImg.GetWidth(), updateBtnImg.GetHeight()); + updateBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); + updateBtn.SetPosition(70, 400); + updateBtn.SetImage(&updateBtnImg); + updateBtn.SetSoundOver(&btnSoundOver); + updateBtn.SetSoundClick(&btnClick); + updateBtn.SetTrigger(&trigA); + updateBtn.SetVisible(false); + updateBtn.SetClickable(false); + updateBtn.SetEffectGrow(); + GuiImageData logo(credits_button_png); GuiImage logoImg(&logo); GuiImageData logoOver(credits_button_over_png); @@ -4295,6 +4619,7 @@ static int MenuSettings() w.Append(&titleTxt); w.Append(&backBtn); w.Append(&lockBtn); + w.Append(&updateBtn); w.Append(btnLogo); w.Append(&homo); //set triggers for tabs @@ -4372,7 +4697,7 @@ static int MenuSettings() sprintf(options2.name[3], "%s",LANGUAGE.Unicodefix); sprintf(options2.name[4], "%s",LANGUAGE.Backgroundmusic); sprintf(options2.name[5], "%s",LANGUAGE.Wiilight); - sprintf(options2.name[6], " "); + sprintf(options2.name[6], "%s",LANGUAGE.Updatepath); sprintf(options2.name[7], "%s",LANGUAGE.MP3Menu); sprintf(options2.name[8], "%s",LANGUAGE.Defaultsettings); @@ -4572,6 +4897,7 @@ static int MenuSettings() mainWindow->Remove(&page3Btn); w.Remove(&backBtn); w.Remove(&lockBtn); + w.Remove(&updateBtn); char entered[20] = ""; strncpy(entered, Settings.unlockCode, sizeof(entered)); int result = OnScreenKeyboard(entered, 20,0); @@ -4582,6 +4908,7 @@ static int MenuSettings() mainWindow->Append(&page3Btn); w.Append(&backBtn); w.Append(&lockBtn); + w.Append(&updateBtn); if ( result == 1 ) { strncpy(Settings.unlockCode, entered, sizeof(Settings.unlockCode)); @@ -4620,6 +4947,7 @@ static int MenuSettings() mainWindow->Remove(&page3Btn); w.Remove(&backBtn); w.Remove(&lockBtn); + w.Remove(&updateBtn); char entered[43] = ""; strncpy(entered, CFG.covers_path, sizeof(entered)); int result = OnScreenKeyboard(entered,43,4); @@ -4630,6 +4958,7 @@ static int MenuSettings() mainWindow->Append(&page3Btn); w.Append(&backBtn); w.Append(&lockBtn); + w.Append(&updateBtn); if ( result == 1 ) { int len = (strlen(entered)-1); @@ -4657,6 +4986,7 @@ static int MenuSettings() mainWindow->Remove(&page3Btn); w.Remove(&backBtn); w.Remove(&lockBtn); + w.Remove(&updateBtn); char entered[43] = ""; strncpy(entered, CFG.disc_path, sizeof(entered)); int result = OnScreenKeyboard(entered, 43,4); @@ -4667,6 +4997,7 @@ static int MenuSettings() mainWindow->Append(&page3Btn); w.Append(&backBtn); w.Append(&lockBtn); + w.Append(&updateBtn); if ( result == 1 ) { int len = (strlen(entered)-1); @@ -4694,6 +5025,7 @@ static int MenuSettings() mainWindow->Remove(&page3Btn); w.Remove(&backBtn); w.Remove(&lockBtn); + w.Remove(&updateBtn); char entered[43] = ""; strncpy(entered, CFG.theme_path, sizeof(entered)); int result = OnScreenKeyboard(entered, 43,4); @@ -4704,6 +5036,7 @@ static int MenuSettings() mainWindow->Append(&page3Btn); w.Append(&backBtn); w.Append(&lockBtn); + w.Append(&updateBtn); if ( result == 1 ) { int len = (strlen(entered)-1); @@ -4745,6 +5078,7 @@ static int MenuSettings() w.Append(&titleTxt); w.Append(&backBtn); w.Append(&lockBtn); + w.Append(&updateBtn); w.Append(btnLogo); mainWindow->Append(&optionBrowser2); @@ -4754,6 +5088,7 @@ static int MenuSettings() mainWindow->Append(&page3Btn); w.Append(&backBtn); w.Append(&lockBtn); + w.Append(&updateBtn); } } else @@ -4818,7 +5153,15 @@ static int MenuSettings() else if (Settings.wiilight == 1) sprintf (options2.value[5],"%s",LANGUAGE.ON); else if (Settings.wiilight == 2) sprintf (options2.value[5],"%s",LANGUAGE.OnlyInstall); - sprintf(options2.value[6], " "); + if (strlen(CFG.update_path) < (9 + 3)) { + sprintf(cfgtext, "%s", CFG.update_path); + } else { + strncpy(cfgtext, CFG.update_path, 9); + cfgtext[9] = '\0'; + strncat(cfgtext, "...", 3); + } + sprintf(options2.value[6], "%s", cfgtext); + sprintf(options2.value[7], "not working!"); sprintf(options2.value[8], " "); @@ -4836,6 +5179,7 @@ static int MenuSettings() mainWindow->Remove(&page3Btn); w.Remove(&backBtn); w.Remove(&lockBtn); + w.Remove(&updateBtn); char entered[43] = ""; strncpy(entered, CFG.titlestxt_path, sizeof(entered)); int result = OnScreenKeyboard(entered,43,4); @@ -4846,6 +5190,7 @@ static int MenuSettings() mainWindow->Append(&page3Btn); w.Append(&backBtn); w.Append(&lockBtn); + w.Append(&updateBtn); if ( result == 1 ) { int len = (strlen(entered)-1); @@ -4876,6 +5221,7 @@ static int MenuSettings() mainWindow->Remove(&page3Btn); w.Remove(&backBtn); w.Remove(&lockBtn); + w.Remove(&updateBtn); char entered[40] = ""; strncpy(entered, CFG.language_path, sizeof(entered)); int result = OnScreenKeyboard(entered, 40,0); @@ -4886,6 +5232,7 @@ static int MenuSettings() mainWindow->Append(&page3Btn); w.Append(&backBtn); w.Append(&lockBtn); + w.Append(&updateBtn); if ( result == 1 ) { strncpy(CFG.language_path, entered, sizeof(CFG.language_path)); if(isSdInserted()) { @@ -4932,6 +5279,40 @@ static int MenuSettings() WindowPrompt(LANGUAGE.NoSDcardinserted, LANGUAGE.InsertaSDCardtousethatoption, LANGUAGE.ok, 0,0,0); } break; + case 6: + if ( CFG.godmode == 1) + { + mainWindow->Remove(&optionBrowser2); + mainWindow->Remove(&page1Btn); + mainWindow->Remove(&page2Btn); + mainWindow->Remove(&tabBtn); + mainWindow->Remove(&page3Btn); + w.Remove(&backBtn); + w.Remove(&lockBtn); + w.Remove(&updateBtn); + char entered[43] = ""; + strncpy(entered, CFG.update_path, sizeof(entered)); + int result = OnScreenKeyboard(entered,43,4); + mainWindow->Append(&optionBrowser2); + mainWindow->Append(&page1Btn); + mainWindow->Append(&page2Btn); + mainWindow->Append(&tabBtn); + mainWindow->Append(&page3Btn); + w.Append(&backBtn); + w.Append(&lockBtn); + w.Append(&updateBtn); + if ( result == 1 ) + { + int len = (strlen(entered)-1); + if(entered[len] !='/') + strncat (entered, "/", 1); + strncpy(CFG.update_path, entered, sizeof(CFG.update_path)); + WindowPrompt(LANGUAGE.Updatepathchanged,0,LANGUAGE.ok,0,0,0); + } + } else { + WindowPrompt(0,LANGUAGE.Consoleshouldbeunlockedtomodifyit,LANGUAGE.ok,0,0,0); + } + break; case 8: int choice = WindowPrompt(LANGUAGE.Areyousure, 0, LANGUAGE.Yes, LANGUAGE.Cancel, 0, 0); if(choice == 1) { @@ -4992,6 +5373,34 @@ static int MenuSettings() break; } + if(updateBtn.GetState() == STATE_CLICKED) { + if(isSdInserted() && CFG.godmode) { + mainWindow->Remove(&optionBrowser2); + mainWindow->Remove(&page1Btn); + mainWindow->Remove(&page2Btn); + mainWindow->Remove(&tabBtn); + mainWindow->Remove(&page3Btn); + w.Remove(&backBtn); + w.Remove(&lockBtn); + w.Remove(&updateBtn); + int ret = ProgressUpdateWindow(); + if(ret < 0) { + WindowPrompt(LANGUAGE.Updatefailed,0,LANGUAGE.ok,0,0,0); + } + mainWindow->Append(&optionBrowser2); + mainWindow->Append(&page1Btn); + mainWindow->Append(&page2Btn); + mainWindow->Append(&tabBtn); + mainWindow->Append(&page3Btn); + w.Append(&backBtn); + w.Append(&lockBtn); + w.Append(&updateBtn); + } else { + WindowPrompt(LANGUAGE.NoSDcardinserted, LANGUAGE.InsertaSDCardtousethatoption, LANGUAGE.ok, 0,0,0); + } + updateBtn.ResetState(); + } + if(lockBtn.GetState() == STATE_CLICKED) { if (!strcmp("", Settings.unlockCode)) @@ -5008,6 +5417,7 @@ static int MenuSettings() mainWindow->Remove(&page3Btn); w.Remove(&backBtn); w.Remove(&lockBtn); + w.Remove(&updateBtn); char entered[20] = ""; int result = OnScreenKeyboard(entered, 20,0); mainWindow->Append(&optionBrowser2); @@ -5017,6 +5427,7 @@ static int MenuSettings() mainWindow->Append(&page3Btn); w.Append(&backBtn); w.Append(&lockBtn); + w.Append(&updateBtn); mainWindow->Append(&tabBtn); if ( result == 1 ) { if (!strcmp(entered, Settings.unlockCode)) //if password correct @@ -5087,6 +5498,13 @@ static int MenuSettings() homo.ResetState(); } } + if(CFG.godmode) { + updateBtn.SetVisible(true); + updateBtn.SetClickable(true); + } else { + updateBtn.SetVisible(false); + updateBtn.SetClickable(false); + } if(settingsbackgroundbtn.GetState() == STATE_CLICKED) { optionBrowser2.SetFocus(1); diff --git a/source/updater.c b/source/updater.c new file mode 100644 index 00000000..625e2cc9 --- /dev/null +++ b/source/updater.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include + +#include "http.h" + +static s32 connection; + +s32 network_request(const char * request) +{ + char buf[1024]; + char *ptr = NULL; + + u32 cnt, size; + s32 ret; + + /* Send request */ + ret = net_send(connection, request, strlen(request), 0); + if (ret < 0) + return ret; + + /* Clear buffer */ + memset(buf, 0, sizeof(buf)); + + /* Read HTTP header */ + for (cnt = 0; !strstr(buf, "\r\n\r\n"); cnt++) + if (net_recv(connection, buf + cnt, 1, 0) <= 0) + return -1; + + /* HTTP request OK? */ + if (!strstr(buf, "HTTP/1.1 200 OK")) + return -1; + /* Retrieve content size */ + ptr = strstr(buf, "Content-Length:"); + if (!ptr) + return -1; + + sscanf(ptr, "Content-Length: %u", &size); + return size; +} + +s32 network_read(void *buf, u32 len) +{ + s32 read = 0, ret; + + /* Data to be read */ + while (read < len) { + /* Read network data */ + ret = net_read(connection, buf + read, len - read); + if (ret < 0) + return ret; + + /* Read finished */ + if (!ret) + break; + + /* Increment read variable */ + read += ret; + } + + return read; +} + +s32 downloadrev(const char * url) { + + //Check if the url starts with "http://", if not it is not considered a valid url + if(strncmp(url, "http://", strlen("http://")) != 0) + { + //printf("URL '%s' doesn't start with 'http://'\n", url); + return -1; + } + + //Locate the path part of the url by searching for '/' past "http://" + char *path = strchr(url + strlen("http://"), '/'); + + //At the very least the url has to end with '/', ending with just a domain is invalid + if(path == NULL) + { + //printf("URL '%s' has no PATH part\n", url); + return -1; + } + + //Extract the domain part out of the url + int domainlength = path - url - strlen("http://"); + + if(domainlength == 0) + { + //printf("No domain part in URL '%s'\n", url); + return -1; + } + + char domain[domainlength + 1]; + strncpy(domain, url + strlen("http://"), domainlength); + domain[domainlength] = '\0'; + + connection = GetConnection(domain); + if(connection < 0) { + return -1; + } + + //Form a nice request header to send to the webserver + char* headerformat = "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n";; + char header[strlen(headerformat) + strlen(domain) + strlen(path)]; + sprintf(header, headerformat, path, domain); + + s32 filesize = network_request(header); + + return filesize; +} + +void CloseConnection() { + + net_close(connection); + +} diff --git a/source/updater.h b/source/updater.h new file mode 100644 index 00000000..7863d5f5 --- /dev/null +++ b/source/updater.h @@ -0,0 +1,18 @@ +#ifndef _UPDATER_H_ +#define _UPDATER_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +s32 network_request(const char * request); +s32 network_read(void *buf, u32 len); +s32 downloadrev(const char * url); +void CloseConnection(); + +#ifdef __cplusplus +} +#endif + +#endif