From a5272b8cf51348ff25c53e5b0858146d9c24b984 Mon Sep 17 00:00:00 2001
From: dborth <dborth@ab33defa-829a-11dd-99d6-6900107db72b>
Date: Fri, 21 Aug 2009 07:20:13 +0000
Subject: [PATCH] text alignment corrections

---
 source/ngc/FreeTypeGX.cpp   | 331 +++++++++++++++++++-----------------
 source/ngc/FreeTypeGX.h     |  45 +++--
 source/ngc/gui/gui_text.cpp |  15 +-
 3 files changed, 210 insertions(+), 181 deletions(-)

diff --git a/source/ngc/FreeTypeGX.cpp b/source/ngc/FreeTypeGX.cpp
index 125476b..5a004ed 100644
--- a/source/ngc/FreeTypeGX.cpp
+++ b/source/ngc/FreeTypeGX.cpp
@@ -24,7 +24,7 @@
 
 static FT_Library ftLibrary;	/**< FreeType FT_Library instance. */
 static FT_Face ftFace;			/**< FreeType reusable FT_Face typographic object. */
-static FT_GlyphSlot ftSlot;	/**< FreeType reusable FT_GlyphSlot glyph container object. */
+static FT_GlyphSlot ftSlot;		/**< FreeType reusable FT_GlyphSlot glyph container object. */
 
 FreeTypeGX *fontSystem[MAX_FONT_SIZE+1];
 
@@ -81,7 +81,8 @@ wchar_t* charToWideChar(const char* strChar)
  * @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(FT_UInt pixelSize, uint8_t textureFormat, uint8_t vertexIndex) {
+FreeTypeGX::FreeTypeGX(FT_UInt pixelSize, uint8_t textureFormat, uint8_t vertexIndex)
+{
 	this->textureFormat = textureFormat;
 	this->setVertexFormat(vertexIndex);
 	this->setCompatibilityMode(FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_PASSCLR | FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE);
@@ -92,7 +93,8 @@ FreeTypeGX::FreeTypeGX(FT_UInt pixelSize, uint8_t textureFormat, uint8_t vertexI
 /**
  * Default destructor for the FreeTypeGX class.
  */
-FreeTypeGX::~FreeTypeGX() {
+FreeTypeGX::~FreeTypeGX()
+{
 	this->unloadFont();
 }
 
@@ -105,9 +107,9 @@ FreeTypeGX::~FreeTypeGX() {
  *
  * @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) {
+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);
@@ -123,7 +125,8 @@ void FreeTypeGX::setVertexFormat(uint8_t vertexIndex) {
  *
  * @param compatibilityMode	Compatibility descritor (FTGX_COMPATIBILITY_*) as defined in FreeTypeGX.h
 */
-void FreeTypeGX::setCompatibilityMode(uint32_t compatibilityMode) {
+void FreeTypeGX::setCompatibilityMode(uint32_t compatibilityMode)
+{
 	this->compatibilityMode = compatibilityMode;
 }
 
@@ -133,9 +136,12 @@ void FreeTypeGX::setCompatibilityMode(uint32_t compatibilityMode) {
  * 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) {
+void FreeTypeGX::setDefaultMode()
+{
+	if(this->compatibilityMode)
+	{
+		switch(this->compatibilityMode & 0x00FF)
+		{
 			case FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_MODULATE:
 				GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
 				break;
@@ -155,7 +161,8 @@ void FreeTypeGX::setDefaultMode() {
 				break;
 		}
 
-		switch(this->compatibilityMode & 0xFF00) {
+		switch(this->compatibilityMode & 0xFF00)
+		{
 			case FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE:
 				GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
 				break;
@@ -179,14 +186,12 @@ void FreeTypeGX::setDefaultMode() {
  *
  * This routine clears all members of the font map structure and frees all allocated memory back to the system.
  */
-void FreeTypeGX::unloadFont() {
+void FreeTypeGX::unloadFont()
+{
 	if(this->fontData.size() == 0)
 		return;
-
-	for( std::map<wchar_t, ftgxCharData>::iterator i = this->fontData.begin(); i != this->fontData.end(); i++) {
+	for(std::map<wchar_t, ftgxCharData>::iterator i = this->fontData.begin(); i != this->fontData.end(); i++)
 		free(i->second.glyphDataTexture);
-	}
-
 	this->fontData.clear();
 }
 
@@ -199,10 +204,12 @@ void FreeTypeGX::unloadFont() {
  * @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 FreeTypeGX::adjustTextureWidth(uint16_t textureWidth, uint8_t textureFormat)
+{
 	uint16_t alignment;
 
-	switch(textureFormat) {
+	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 */
@@ -218,7 +225,6 @@ uint16_t FreeTypeGX::adjustTextureWidth(uint16_t textureWidth, uint8_t textureFo
 			break;
 	}
 	return textureWidth % alignment == 0 ? textureWidth : alignment + textureWidth - (textureWidth % alignment);
-
 }
 
 /**
@@ -230,10 +236,12 @@ uint16_t FreeTypeGX::adjustTextureWidth(uint16_t textureWidth, uint8_t textureFo
  * @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 FreeTypeGX::adjustTextureHeight(uint16_t textureHeight, uint8_t textureFormat)
+{
 	uint16_t alignment;
 
-	switch(textureFormat) {
+	switch(textureFormat)
+	{
 		case GX_TF_I4:		/* 8x8 Tiles - 4-bit Intensity */
 			alignment = 8;
 			break;
@@ -249,7 +257,6 @@ uint16_t FreeTypeGX::adjustTextureHeight(uint16_t textureHeight, uint8_t texture
 			break;
 	}
 	return textureHeight % alignment == 0 ? textureHeight : alignment + textureHeight - (textureHeight % alignment);
-
 }
 
 /**
@@ -261,7 +268,8 @@ uint16_t FreeTypeGX::adjustTextureHeight(uint16_t textureHeight, uint8_t texture
  * @param charCode	The requested glyph's character code.
  * @return A pointer to the allocated font structure.
  */
-ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode) {
+ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode)
+{
 	FT_UInt gIndex;
 	uint16_t textureWidth = 0, textureHeight = 0;
 
@@ -276,13 +284,14 @@ ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode) {
 			textureHeight = adjustTextureHeight(glyphBitmap->rows, this->textureFormat);
 
 			this->fontData[charCode] = (ftgxCharData){
+				ftSlot->bitmap_left,
 				ftSlot->advance.x >> 6,
 				gIndex,
 				textureWidth,
 				textureHeight,
 				ftSlot->bitmap_top,
 				ftSlot->bitmap_top,
-				textureHeight - ftSlot->bitmap_top,
+				glyphBitmap->rows - ftSlot->bitmap_top,
 				NULL
 			};
 			this->loadGlyphData(glyphBitmap, &this->fontData[charCode]);
@@ -290,7 +299,6 @@ ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode) {
 			return &this->fontData[charCode];
 		}
 	}
-
 	return NULL;
 }
 
@@ -300,19 +308,17 @@ ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode) {
  * 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 FreeTypeGX::cacheGlyphDataComplete()
+{
 	uint16_t i = 0;
 	FT_UInt gIndex;
 	FT_ULong charCode = FT_Get_First_Char( ftFace, &gIndex );
-	while ( gIndex != 0 ) {
-
-		if(this->cacheGlyphData(charCode) != NULL) {
+	while ( gIndex != 0 )
+	{
+		if(this->cacheGlyphData(charCode) != NULL)
 			i++;
-		}
-
 		charCode = FT_Get_Next_Char( ftFace, charCode, &gIndex );
 	}
-
 	return i;
 }
 
@@ -325,19 +331,22 @@ uint16_t FreeTypeGX::cacheGlyphDataComplete() {
  * @param bmp	A pointer to the most recently rendered glyph's bitmap.
  * @param charData	A pointer to an allocated ftgxCharData structure whose data represent that of the last rendered glyph.
  */
-void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData) {
-
+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++) {
+	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) {
+	switch(this->textureFormat)
+	{
 		case GX_TF_I4:
 			charData->glyphDataTexture = Metaphrasis::convertBufferToI4(glyphData, charData->textureWidth, charData->textureHeight);
 			break;
@@ -361,7 +370,6 @@ void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData) {
 			charData->glyphDataTexture = Metaphrasis::convertBufferToRGBA8(glyphData, charData->textureWidth, charData->textureHeight);
 			break;
 	}
-
 	free(glyphData);
 }
 
@@ -373,18 +381,14 @@ void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData) {
  * @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 ) {
+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;
-	}
-
+	else if (format & FTGX_JUSTIFY_CENTER)
+		return -(width >> 1);
+	else if (format & FTGX_JUSTIFY_RIGHT)
+		return -width;
 	return 0;
 }
 
@@ -396,17 +400,32 @@ uint16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format) {
  * @param offset	Current pixel offset data of the string.
  * @param format	Positional format of the string.
  */
-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;
-	}
+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;
 }
 
@@ -423,47 +442,57 @@ uint16_t FreeTypeGX::getStyleOffsetHeight(ftgxDataOffset offset, uint16_t format
  * @param textStyle	Flags which specify any styling which should be applied to the rendered string.
  * @return The number of characters printed.
  */
-uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, wchar_t *text, GXColor color, uint16_t textStyle) {
+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 & 0x000F) {
+	if(textStyle & FTGX_JUSTIFY_MASK)
+	{
 		x_offset = this->getStyleOffsetWidth(this->getWidth(text), textStyle);
 	}
-	if(textStyle & 0x00F0) {
-		y_offset = this->getStyleOffsetHeight(this->getOffset(text), textStyle);
+	if(textStyle & FTGX_ALIGN_MASK)
+	{
+		this->getOffset(text, &offset);
+		y_offset = this->getStyleOffsetHeight(&offset, textStyle);
 	}
 
-	for (uint16_t i = 0; i < strLength; i++) {
-
+	for (uint16_t i = 0; i < strLength; i++)
+	{
 		ftgxCharData* glyphData = NULL;
-		if( this->fontData.find(text[i]) != this->fontData.end() ) {
+		if( this->fontData.find(text[i]) != this->fontData.end() )
+		{
 			glyphData = &this->fontData[text[i]];
 		}
-		else {
+		else
+		{
 			glyphData = this->cacheGlyphData(text[i]);
 		}
 
-		if(glyphData != NULL) {
-
-			if(this->ftKerningEnabled && i) {
+		if(glyphData != NULL)
+		{
+			if(this->ftKerningEnabled && i)
+			{
 				FT_Get_Kerning( 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 - x_offset, y - glyphData->renderOffsetY - y_offset, color);
+			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);
+	if(textStyle & FTGX_STYLE_MASK)
+	{
+		this->getOffset(text, &offset);
+		this->drawTextFeature(x + x_offset, y + y_offset, this->getWidth(text), &offset, textStyle, color);
 	}
 
 	return printed;
@@ -472,46 +501,20 @@ uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, wchar_t *text, GXColor color
 /**
  * \overload
  */
-uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, wchar_t const *text, GXColor color, uint16_t textStyle) {
+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) {
+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_UNDERLINE)
+		this->copyFeatureToFramebuffer(width, featureHeight, x, y + 1, color);
 
-	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;
-		}
-	}
+	if (format & FTGX_STYLE_STRIKE)
+		this->copyFeatureToFramebuffer(width, featureHeight, x, y - ((offsetData->max) >> 1), color);
 }
 
 /**
@@ -523,31 +526,35 @@ void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, uint16_t width, ftgxDataO
  * @param text	NULL terminated string to calculate.
  * @return The width of the text string in pixels.
  */
-uint16_t FreeTypeGX::getWidth(wchar_t *text) {
+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++) {
+	for (uint16_t i = 0; i < strLength; i++)
+	{
 
 		ftgxCharData* glyphData = NULL;
-		if( this->fontData.find(text[i]) != this->fontData.end() ) {
+		if( this->fontData.find(text[i]) != this->fontData.end() )
+		{
 			glyphData = &this->fontData[text[i]];
 		}
-		else {
+		else
+		{
 			glyphData = this->cacheGlyphData(text[i]);
 		}
 
-		if(glyphData != NULL) {
-			if(this->ftKerningEnabled && (i > 0)) {
+		if(glyphData != NULL)
+		{
+			if(this->ftKerningEnabled && (i > 0))
+			{
 				FT_Get_Kerning( ftFace, this->fontData[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta );
 				strWidth += pairDelta.x >> 6;
 			}
-
 			strWidth += glyphData->glyphAdvanceX;
 		}
 	}
-
 	return strWidth;
 }
 
@@ -555,7 +562,8 @@ uint16_t FreeTypeGX::getWidth(wchar_t *text) {
  *
  * \overload
  */
-uint16_t FreeTypeGX::getWidth(wchar_t const *text) {
+uint16_t FreeTypeGX::getWidth(wchar_t const *text)
+{
 	return this->getWidth((wchar_t *)text);
 }
 
@@ -568,17 +576,19 @@ uint16_t FreeTypeGX::getWidth(wchar_t const *text) {
  * @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;
+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) {
+uint16_t FreeTypeGX::getHeight(wchar_t const *text)
+{
 	return this->getHeight((wchar_t *)text);
 }
 
@@ -589,37 +599,46 @@ uint16_t FreeTypeGX::getHeight(wchar_t const *text) {
  * 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.
+ * @param offset returns the max and min values above and below the font origin line
+ *
  */
-ftgxDataOffset FreeTypeGX::getOffset(wchar_t *text) {
+void FreeTypeGX::getOffset(wchar_t *text, ftgxDataOffset* offset)
+{
 	uint16_t strLength = wcslen(text);
-	uint16_t strMax = 0, strMin = 0;
+	int16_t strMax = 0, strMin = 9999;
 
-	for (uint16_t i = 0; i < strLength; i++) {
+	for (uint16_t i = 0; i < strLength; i++)
+	{
 
 		ftgxCharData* glyphData = NULL;
-		if( this->fontData.find(text[i]) != this->fontData.end() ) {
+		if( this->fontData.find(text[i]) != this->fontData.end() )
+		{
 			glyphData = &this->fontData[text[i]];
 		}
-		else {
+		else
+		{
 			glyphData = this->cacheGlyphData(text[i]);
 		}
 
-		if(glyphData != NULL) {
+		if(glyphData != NULL)
+		{
 			strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax;
-			strMin = glyphData->renderOffsetMin > strMin ? glyphData->renderOffsetMin : strMin;
+			strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin;
 		}
 	}
-
-	return (ftgxDataOffset){strMax, strMin};
+	offset->ascender = ftFace->size->metrics.ascender>>6;
+	offset->descender = ftFace->size->metrics.descender>>6;
+	offset->max = strMax;
+	offset->min = strMin;
 }
 
 /**
  *
  * \overload
  */
-ftgxDataOffset FreeTypeGX::getOffset(wchar_t const *text) {
-	return this->getOffset(text);
+void FreeTypeGX::getOffset(wchar_t const *text, ftgxDataOffset* offset)
+{
+	this->getOffset(text, offset);
 }
 
 /**
@@ -634,8 +653,8 @@ ftgxDataOffset FreeTypeGX::getOffset(wchar_t const *text) {
  * @param screenY	The screen Y coordinate at which to output the rendered texture.
  * @param color	Color to apply to the texture.
  */
-void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, GXColor color) {
-
+void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, GXColor color)
+{
 	GX_LoadTexObj(texObj, GX_TEXMAP0);
 	GX_InvalidateTexAll();
 
@@ -643,21 +662,21 @@ void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 te
 	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(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, 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(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_Position2s16(screenX, texHeight + screenY);
+	GX_Color4u8(color.r, color.g, color.b, color.a);
+	GX_TexCoord2f32(0.0f, 1.0f);
 	GX_End();
 	GX_DrawDone();
 
@@ -675,23 +694,23 @@ void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 te
  * @param screenY	The screen Y coordinate at which to output the quad.
  * @param color	Color to apply to the texture.
  */
-void FreeTypeGX::copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, GXColor color) {
-
+void FreeTypeGX::copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, 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(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, 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(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_Position2s16(screenX, featureHeight + screenY);
+	GX_Color4u8(color.r, color.g, color.b, color.a);
 	GX_End();
 	GX_DrawDone();
 
diff --git a/source/ngc/FreeTypeGX.h b/source/ngc/FreeTypeGX.h
index 2ed6a82..881d2fe 100644
--- a/source/ngc/FreeTypeGX.h
+++ b/source/ngc/FreeTypeGX.h
@@ -169,15 +169,16 @@
  * Font face character glyph relevant data structure.
  */
 typedef struct ftgxCharData_ {
-	uint16_t glyphAdvanceX;	/**< Character glyph X coordinate advance in pixels. */
-	uint16_t glyphIndex;	/**< Charachter glyph index in the font face. */
+	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. */
+	uint16_t textureWidth;		/**< Texture width in pixels/bytes. */
+	uint16_t textureHeight;		/**< Texture glyph height in pixels/bytes. */
 
-	uint16_t renderOffsetY;	/**< Texture Y axis bearing offset. */
-	uint16_t renderOffsetMax;	/**< Texture Y axis bearing maximum value. */
-	uint16_t renderOffsetMin;	/**< Texture Y axis bearing minimum value. */
+	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;
@@ -187,23 +188,35 @@ typedef struct ftgxCharData_ {
  * 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. */
+	int16_t ascender;	/**< Maximum data offset. */
+	int16_t descender;	/**< Minimum data offset. */
+	int16_t max;		/**< Maximum data offset. */
+	int16_t min;		/**< Minimum data offset. */
 } ftgxDataOffset;
 
+typedef struct ftgxCharData_ ftgxCharData;
+typedef struct ftgxDataOffset_ ftgxDataOffset;
+
 #define _TEXT(t) L ## t /**< Unicode helper macro. */
 
 #define FTGX_NULL				0x0000
 #define FTGX_JUSTIFY_LEFT		0x0001
 #define FTGX_JUSTIFY_CENTER		0x0002
 #define FTGX_JUSTIFY_RIGHT		0x0004
+#define FTGX_JUSTIFY_MASK		0x000f
 
 #define FTGX_ALIGN_TOP			0x0010
 #define FTGX_ALIGN_MIDDLE		0x0020
 #define FTGX_ALIGN_BOTTOM		0x0040
+#define FTGX_ALIGN_BASELINE		0x0080
+#define FTGX_ALIGN_GLYPH_TOP	0x0100
+#define FTGX_ALIGN_GLYPH_MIDDLE	0x0200
+#define FTGX_ALIGN_GLYPH_BOTTOM	0x0400
+#define FTGX_ALIGN_MASK			0x0ff0
 
-#define FTGX_STYLE_UNDERLINE	0x0100
-#define FTGX_STYLE_STRIKE		0x0200
+#define FTGX_STYLE_UNDERLINE	0x1000
+#define FTGX_STYLE_STRIKE		0x2000
+#define FTGX_STYLE_MASK			0xf000
 
 #define FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_MODULATE	0X0001
 #define FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_DECAL		0X0002
@@ -250,8 +263,8 @@ class FreeTypeGX {
 		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);
+		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);
@@ -260,7 +273,7 @@ class FreeTypeGX {
 
 		void setDefaultMode();
 
-		void drawTextFeature(int16_t x, int16_t y, uint16_t width, ftgxDataOffset offsetData, uint16_t format, GXColor color);
+		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);
 
@@ -278,8 +291,8 @@ class FreeTypeGX {
 		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);
+		void getOffset(wchar_t *text, ftgxDataOffset* offset);
+		void getOffset(wchar_t const *text, ftgxDataOffset* offset);
 };
 
 #endif /* FREETYPEGX_H_ */
diff --git a/source/ngc/gui/gui_text.cpp b/source/ngc/gui/gui_text.cpp
index 2c8027c..cf6648f 100644
--- a/source/ngc/gui/gui_text.cpp
+++ b/source/ngc/gui/gui_text.cpp
@@ -227,11 +227,6 @@ void GuiText::Draw()
 		currentSize = newSize;
 	}
 
-	int voffset = 0;
-
-	if(alignmentVert == ALIGN_MIDDLE)
-		voffset = -newSize/2 + 2;
-
 	if(maxWidth > 0)
 	{
 		char * tmpText = strdup(origText);
@@ -279,7 +274,7 @@ void GuiText::Draw()
 				}
 			}
 			if(textDyn)
-				fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop()+voffset, textDyn, c, style);
+				fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), textDyn, c, style);
 		}
 		else if(wrap)
 		{
@@ -328,8 +323,10 @@ void GuiText::Draw()
 				i++;
 			}
 
+			int voffset = 0;
+
 			if(alignmentVert == ALIGN_MIDDLE)
-				voffset = voffset - (lineheight*linenum)/2 + lineheight/2;
+				voffset = -(lineheight*linenum)/2 + lineheight/2;
 
 			for(i=0; i < linenum; i++)
 			{
@@ -339,13 +336,13 @@ void GuiText::Draw()
 		}
 		else
 		{
-			fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop()+voffset, textDyn, c, style);
+			fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), textDyn, c, style);
 		}
 		free(tmpText);
 	}
 	else
 	{
-		fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop()+voffset, text, c, style);
+		fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), text, c, style);
 	}
 	this->UpdateEffects();
 }