Browse Source

Completed Phase 1 of the TextSprite

This completes the TextSprite by implementing all the basic features
needed and setting up script functions to control those features.  Phase
2 will allow control of certain aspects of individual characters.
Peter Robinson 9 years ago
parent
commit
756c55b2d6

+ 2 - 0
engine/compilers/VisualStudio 2013/Torque 2D.vcxproj

@@ -768,6 +768,8 @@
     <ClInclude Include="..\..\source\audio\vorbisStreamSource.h" />
     <ClInclude Include="..\..\source\audio\vorbisStreamSource.h" />
     <ClInclude Include="..\..\source\bitmapFont\BitmapFont.h" />
     <ClInclude Include="..\..\source\bitmapFont\BitmapFont.h" />
     <ClInclude Include="..\..\source\bitmapFont\BitmapFontCharacter.h" />
     <ClInclude Include="..\..\source\bitmapFont\BitmapFontCharacter.h" />
+    <ClInclude Include="..\..\source\bitmapFont\BitmapFontCharacterInfo.h" />
+    <ClInclude Include="..\..\source\bitmapFont\BitmapFontLineInfo.h" />
     <ClInclude Include="..\..\source\Box2D\Box2D.h" />
     <ClInclude Include="..\..\source\Box2D\Box2D.h" />
     <ClInclude Include="..\..\source\Box2D\Collision\b2BroadPhase.h" />
     <ClInclude Include="..\..\source\Box2D\Collision\b2BroadPhase.h" />
     <ClInclude Include="..\..\source\Box2D\Collision\b2Collision.h" />
     <ClInclude Include="..\..\source\Box2D\Collision\b2Collision.h" />

+ 6 - 0
engine/compilers/VisualStudio 2013/Torque 2D.vcxproj.filters

@@ -3192,6 +3192,12 @@
     <ClInclude Include="..\..\source\2d\sceneobject\TextSprite_ScriptBinding.h">
     <ClInclude Include="..\..\source\2d\sceneobject\TextSprite_ScriptBinding.h">
       <Filter>2d\sceneobject</Filter>
       <Filter>2d\sceneobject</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\..\source\bitmapFont\BitmapFontCharacterInfo.h">
+      <Filter>bitmapFont</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\bitmapFont\BitmapFontLineInfo.h">
+      <Filter>bitmapFont</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">

+ 532 - 64
engine/source/2d/sceneobject/TextSprite.cc

@@ -35,50 +35,222 @@
 // Script bindings.
 // Script bindings.
 #include "TextSprite_ScriptBinding.h"
 #include "TextSprite_ScriptBinding.h"
 
 
+//-----------------------------------------------------------------------------
+// Text Alignment
+//-----------------------------------------------------------------------------
+
+bool TextSprite::setTextAlignment(void* obj, const char* data)
+{
+   static_cast<TextSprite*>(obj)->setTextAlignment(getTextAlignmentEnum(data)); return false;
+}
+
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
-static EnumTable::Enums textAlignmentEnums[] = 
+static EnumTable::Enums textAlignmentEnums[] =
 {
 {
-    { TextSprite::ALIGN_LEFT,      "Left" },
-    { TextSprite::ALIGN_CENTER, "Center" },
-    { TextSprite::ALIGN_RIGHT, "Right" },
-    { TextSprite::ALIGN_JUSTIFY, "Justify" },
+   { TextSprite::ALIGN_LEFT, "Left" },
+   { TextSprite::ALIGN_CENTER, "Center" },
+   { TextSprite::ALIGN_RIGHT, "Right" },
+   { TextSprite::ALIGN_JUSTIFY, "Justify" },
 };
 };
 
 
-static EnumTable gTextAlignmentTable(4, &textAlignmentEnums[0]); 
+static EnumTable gTextAlignmentTable(4, &textAlignmentEnums[0]);
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 TextSprite::TextAlign TextSprite::getTextAlignmentEnum(const char* label)
 TextSprite::TextAlign TextSprite::getTextAlignmentEnum(const char* label)
 {
 {
-    // Search for Mnemonic.
-    for (U32 i = 0; i < (sizeof(textAlignmentEnums) / sizeof(EnumTable::Enums)); i++)
-    {
-        if( dStricmp(textAlignmentEnums[i].label, label) == 0)
-            return (TextAlign)textAlignmentEnums[i].index;
-    }
+   // Search for Mnemonic.
+   for (U32 i = 0; i < (sizeof(textAlignmentEnums) / sizeof(EnumTable::Enums)); i++)
+   {
+      if (dStricmp(textAlignmentEnums[i].label, label) == 0)
+         return (TextAlign)textAlignmentEnums[i].index;
+   }
 
 
-    // Warn.
-    Con::warnf("TextSprite::getTextAlignmentEnum() - Invalid text alignment of '%s'", label );
+   // Warn.
+   Con::warnf("TextSprite::getTextAlignmentEnum() - Invalid text alignment of '%s'", label);
 
 
-    return TextSprite::INVALID_ALIGN;
+   return TextSprite::INVALID_ALIGN;
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 const char* TextSprite::getTextAlignmentDescription(const TextSprite::TextAlign alignment)
 const char* TextSprite::getTextAlignmentDescription(const TextSprite::TextAlign alignment)
 {
 {
-    // Search for Mnemonic.
-    for (U32 i = 0; i < (sizeof(textAlignmentEnums) / sizeof(EnumTable::Enums)); i++)
-    {
-        if( textAlignmentEnums[i].index == alignment )
-            return textAlignmentEnums[i].label;
-    }
+   // Search for Mnemonic.
+   for (U32 i = 0; i < (sizeof(textAlignmentEnums) / sizeof(EnumTable::Enums)); i++)
+   {
+      if (textAlignmentEnums[i].index == alignment)
+         return textAlignmentEnums[i].label;
+   }
+
+   // Warn.
+   Con::warnf("TextSprite::getTextAlignmentDescription() - Invalid text alignment.");
+
+   return StringTable->EmptyString;
+}
+
+//-----------------------------------------------------------------------------
+// Verticle Text Alignment
+//-----------------------------------------------------------------------------
+
+bool TextSprite::setTextVAlignment(void* obj, const char* data)
+{
+   static_cast<TextSprite*>(obj)->setTextVAlignment(getTextVAlignmentEnum(data)); return false;
+}
+
+//------------------------------------------------------------------------------
+
+static EnumTable::Enums textVAlignmentEnums[] =
+{
+   { TextSprite::VALIGN_TOP, "Top" },
+   { TextSprite::VALIGN_MIDDLE, "Middle" },
+   { TextSprite::VALIGN_BOTTOM, "Bottom" },
+};
+
+static EnumTable gTextVAlignmentTable(3, &textVAlignmentEnums[0]);
+
+//-----------------------------------------------------------------------------
+
+TextSprite::TextVAlign TextSprite::getTextVAlignmentEnum(const char* label)
+{
+   // Search for Mnemonic.
+   for (U32 i = 0; i < (sizeof(textVAlignmentEnums) / sizeof(EnumTable::Enums)); i++)
+   {
+      if (dStricmp(textVAlignmentEnums[i].label, label) == 0)
+         return (TextVAlign)textVAlignmentEnums[i].index;
+   }
+
+   // Warn.
+   Con::warnf("TextSprite::getTextVAlignmentEnum() - Invalid vertical text alignment of '%s'", label);
+
+   return TextSprite::INVALID_VALIGN;
+}
+
+//-----------------------------------------------------------------------------
+
+const char* TextSprite::getTextVAlignmentDescription(const TextSprite::TextVAlign alignment)
+{
+   // Search for Mnemonic.
+   for (U32 i = 0; i < (sizeof(textVAlignmentEnums) / sizeof(EnumTable::Enums)); i++)
+   {
+      if (textVAlignmentEnums[i].index == alignment)
+         return textVAlignmentEnums[i].label;
+   }
+
+   // Warn.
+   Con::warnf("TextSprite::getTextVAlignmentDescription() - Invalid vertical text alignment.");
+
+   return StringTable->EmptyString;
+}
+
+//-----------------------------------------------------------------------------
+// Overflow Mode X
+//-----------------------------------------------------------------------------
+
+bool TextSprite::setOverflowModeX(void* obj, const char* data)
+{
+   static_cast<TextSprite*>(obj)->setOverflowModeX(getOverflowModeXEnum(data)); return false;
+}
+
+//------------------------------------------------------------------------------
+
+static EnumTable::Enums overflowModeXEnums[] =
+{
+   { TextSprite::OVERFLOW_X_WRAP, "Wrap" },
+   { TextSprite::OVERFLOW_X_VISIBLE, "Visible" },
+   { TextSprite::OVERFLOW_X_HIDDEN, "Hidden" },
+   { TextSprite::OVERFLOW_X_SHRINK, "Shrink" },
+};
+
+static EnumTable gOverflowModeXTable(4, &overflowModeXEnums[0]);
+
+//-----------------------------------------------------------------------------
+
+TextSprite::OverflowModeX TextSprite::getOverflowModeXEnum(const char* label)
+{
+   // Search for Mnemonic.
+   for (U32 i = 0; i < (sizeof(overflowModeXEnums) / sizeof(EnumTable::Enums)); i++)
+   {
+      if (dStricmp(overflowModeXEnums[i].label, label) == 0)
+         return (OverflowModeX)overflowModeXEnums[i].index;
+   }
+
+   // Warn.
+   Con::warnf("TextSprite::getOverflowModeXEnum() - Invalid overflow mode X of '%s'", label);
+
+   return TextSprite::INVALID_OVERFLOW_X;
+}
+
+//-----------------------------------------------------------------------------
+
+const char* TextSprite::getOverflowModeXDescription(const TextSprite::OverflowModeX modeX)
+{
+   // Search for Mnemonic.
+   for (U32 i = 0; i < (sizeof(overflowModeXEnums) / sizeof(EnumTable::Enums)); i++)
+   {
+      if (overflowModeXEnums[i].index == modeX)
+         return overflowModeXEnums[i].label;
+   }
+
+   // Warn.
+   Con::warnf("TextSprite::getOverflowModeXDescription() - Invalid overflow mode X.");
+
+   return StringTable->EmptyString;
+}
+
+//-----------------------------------------------------------------------------
+// Overflow Mode Y
+//-----------------------------------------------------------------------------
+
+bool TextSprite::setOverflowModeY(void* obj, const char* data)
+{
+   static_cast<TextSprite*>(obj)->setOverflowModeY(getOverflowModeYEnum(data)); return false;
+}
+
+//------------------------------------------------------------------------------
+
+static EnumTable::Enums overflowModeYEnums[] =
+{
+   { TextSprite::OVERFLOW_Y_VISIBLE, "Visible" },
+   { TextSprite::OVERFLOW_Y_HIDDEN, "Hidden" },
+   { TextSprite::OVERFLOW_Y_SHRINK, "Shrink" },
+};
+
+static EnumTable gOverflowModeYTable(3, &overflowModeYEnums[0]);
+
+//-----------------------------------------------------------------------------
 
 
-    // Warn.
-    Con::warnf( "TextSprite::getTextAlignmentDescription() - Invalid text alignment.");
+TextSprite::OverflowModeY TextSprite::getOverflowModeYEnum(const char* label)
+{
+   // Search for Mnemonic.
+   for (U32 i = 0; i < (sizeof(overflowModeYEnums) / sizeof(EnumTable::Enums)); i++)
+   {
+      if (dStricmp(overflowModeYEnums[i].label, label) == 0)
+         return (OverflowModeY)overflowModeYEnums[i].index;
+   }
+
+   // Warn.
+   Con::warnf("TextSprite::getOverflowModeYEnum() - Invalid overflow mode Y of '%s'", label);
 
 
-    return StringTable->EmptyString;
+   return TextSprite::INVALID_OVERFLOW_Y;
+}
+
+//-----------------------------------------------------------------------------
+
+const char* TextSprite::getOverflowModeYDescription(const TextSprite::OverflowModeY modeY)
+{
+   // Search for Mnemonic.
+   for (U32 i = 0; i < (sizeof(overflowModeYEnums) / sizeof(EnumTable::Enums)); i++)
+   {
+      if (overflowModeYEnums[i].index == modeY)
+         return overflowModeYEnums[i].label;
+   }
+
+   // Warn.
+   Con::warnf("TextSprite::getOverflowModeYDescription() - Invalid overflow mode Y.");
+
+   return StringTable->EmptyString;
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -97,7 +269,9 @@ TextSprite::TextSprite() :
    mOverflowY(TextSprite::OVERFLOW_Y_HIDDEN),
    mOverflowY(TextSprite::OVERFLOW_Y_HIDDEN),
    mAutoLineHeight(true),
    mAutoLineHeight(true),
    mCustomLineHeight(1.0f),
    mCustomLineHeight(1.0f),
-   mKerning(0.0f)
+   mKerning(0.0f),
+   mFontSpatialsDirty(true),
+   mCalculatedSize(1.0f, 1.0f)
 {
 {
 }
 }
 
 
@@ -115,10 +289,17 @@ void TextSprite::initPersistFields()
     Parent::initPersistFields();
     Parent::initPersistFields();
 
 
     addProtectedField("font", TypeFontAssetPtr, Offset(mFontAsset, TextSprite), &setFont, &getFont, &writeFont, "");
     addProtectedField("font", TypeFontAssetPtr, Offset(mFontAsset, TextSprite), &setFont, &getFont, &writeFont, "");
-    addProtectedField("text", TypeString, 0, setText, getText, &writeText, "The text to be displayed." );  
-    //addProtectedField("textAlignment", TypeEnum, Offset(mTextAlignment, TextSprite), &setTextAlignment, &defaultProtectedGetFn, &writeTextAlignment, 1, &gTextAlignmentTable, "");
-    addProtectedField("fontSize", TypeVector2, Offset(mFontSize, TextSprite), &setFontSize, &defaultProtectedGetFn,&writeFontSize, "" );
-    //addProtectedField("fontPadding", TypeF32, Offset(mFontPadding, TextSprite), &setFontPadding, &defaultProtectedGetFn, &writeFontPadding, "" );
+    addProtectedField("text", TypeString, 0, setText, getText, &writeText, "The text to be displayed.");
+    addProtectedField("fontSize", TypeVector2, Offset(mFontSize, TextSprite), &setFontSize, &defaultProtectedGetFn, &writeFontSize, "");
+    addProtectedField("fontScaleX", TypeF32, Offset(mFontScaleX, TextSprite), &setFontScaleX, &defaultProtectedGetFn, &writeFontScaleX, "");
+    addProtectedField("fontScaleY", TypeF32, Offset(mFontScaleY, TextSprite), &setFontScaleY, &defaultProtectedGetFn, &writeFontScaleY, "");
+    addProtectedField("textAlign", TypeEnum, Offset(mTextAlign, TextSprite), &setTextAlignment, &defaultProtectedGetFn, &writeTextAlignment, 1, &gTextAlignmentTable, "");
+    addProtectedField("textVAlign", TypeEnum, Offset(mTextVAlign, TextSprite), &setTextVAlignment, &defaultProtectedGetFn, &writeTextVAlignment, 1, &gTextVAlignmentTable, "");
+    addProtectedField("overflowModeX", TypeEnum, Offset(mOverflowX, TextSprite), &setOverflowModeX, &defaultProtectedGetFn, &writeOverflowModeX, 1, &gOverflowModeXTable, "");
+    addProtectedField("overflowModeY", TypeEnum, Offset(mOverflowY, TextSprite), &setOverflowModeY, &defaultProtectedGetFn, &writeOverflowModeY, 1, &gOverflowModeYTable, "");
+    addField("autoLineHeight", TypeBool, Offset(mAutoLineHeight, TextSprite), &writeAutoLineHeight, "");
+    addProtectedField("customLineHeight", TypeF32, Offset(mCustomLineHeight, TextSprite), &setCustomLineHeight, &defaultProtectedGetFn, &writeCustomLineHeight, "");
+    addProtectedField("kerning", TypeF32, Offset(mKerning, TextSprite), &setKerning, &defaultProtectedGetFn, &writeKerning, "");
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -192,19 +373,112 @@ void TextSprite::sceneRender( const SceneRenderState* pSceneRenderState, const S
     if( renderCharacters == 0 )
     if( renderCharacters == 0 )
         return;
         return;
 
 
+    //Make sure none of our settings are invalid
+    if (mTextAlign == INVALID_ALIGN)
+    {
+       mTextAlign = ALIGN_LEFT;
+    }
+
+    if (mTextVAlign == INVALID_VALIGN)
+    {
+       mTextVAlign = VALIGN_TOP;
+    }
+
+    if (mOverflowX == INVALID_OVERFLOW_X)
+    {
+       mOverflowX = OVERFLOW_X_WRAP;
+    }
+
+    if (mOverflowY == INVALID_OVERFLOW_Y)
+    {
+       mOverflowY = OVERFLOW_Y_HIDDEN;
+    }
+
     // Get a size ratio
     // Get a size ratio
     const F32 ratio = mFontAsset->mBitmapFont.getSizeRatio(mFontSize);
     const F32 ratio = mFontAsset->mBitmapFont.getSizeRatio(mFontSize);
 
 
+    //get the line height
+    const F32 lineHeight = GetLineHeight();
+
+    //prep for justify
+    if (mTextAlign == ALIGN_JUSTIFY)
+    {
+       mKerning = 0;
+    }
+
+    //determine the rows
+    if (mFontSpatialsDirty || mSize != mCalculatedSize)
+    {
+       CalculateSpatials(ratio);
+    }
+
+    // If we're shrinking the set the scale
+    bool shrinkX = false;
+    bool shrinkY = false;
+    F32 origScaleX, origScaleY;
+    F32 origLengthX;
+    if (mOverflowX == OVERFLOW_X_SHRINK && mLine.front().mLength > mSize.x)
+    {
+       shrinkX = true;
+       origScaleX = mFontScaleX;
+       mFontScaleX = mSize.x / mLine.front().mLength;
+       origLengthX = mLine.front().mLength;
+       mLine.front().mLength = mSize.x;
+    }
+    if (mOverflowY == OVERFLOW_Y_SHRINK && (mLine.size() * lineHeight * mFontScaleY) > mSize.y)
+    {
+       shrinkY = true;
+       origScaleY = mFontScaleY;
+       mFontScaleY = mSize.y / (mLine.size() * lineHeight);
+    }
+
     // Create a cursor
     // Create a cursor
-    Vector2 cursor(0.0f, mFontAsset->mBitmapFont.mBaseline * ratio);
+    Vector2 cursor(0.0f, 0.0f);
+
+    ApplyAlignment(cursor, mLine.size(), 0, mLine.front().mLength, mLine.front().mEnd - mLine.front().mStart + 1, ratio);
 
 
-    // Render all the characters.    
-    for( U32 characterIndex = 0; characterIndex < renderCharacters; ++characterIndex )
+    // Render all the characters.  
+    U32 row = 0;
+    S32 prevCharID = -1;
+    for (U32 characterIndex = mLine.front().mStart; characterIndex < renderCharacters; ++characterIndex)
     {
     {
         // Fetch character.
         // Fetch character.
-        U32 character = mText.getChar( characterIndex );
+        U32 charID = mText.getChar( characterIndex );
+
+        if (characterIndex >= mLine[row].mStart)
+        {
+           RenderLetter(pBatchRenderer, cursor, charID, ratio);
+        }
+        
+        if ((row + 1) < mLine.size() && mLine[row + 1].mStart == (characterIndex + 1))
+        {
+           row++;
+           cursor.x = 0;
+           prevCharID = -1;
+           ApplyAlignment(cursor, mLine.size(), row, mLine[row].mLength, mLine[row].mEnd - mLine[row].mStart + 1, ratio);
+        }
+        else
+        {
+           cursor.x += getCursorAdvance(charID, prevCharID, ratio);
+           prevCharID = charID;
+        }
+    }
+
+    //clean up for justify
+    if (mTextAlign == ALIGN_JUSTIFY)
+    {
+       mKerning = 0;
+    }
 
 
-        RenderLetter(pBatchRenderer, cursor, character, ratio);
+    //clean up scale
+    if (mOverflowX == OVERFLOW_X_SHRINK && shrinkX)
+    {
+       mFontScaleX = origScaleX;
+       mLine.front().mLength = origLengthX;
+    }
+    if (mOverflowY == OVERFLOW_Y_SHRINK && shrinkY)
+    {
+       mFontScaleY = origScaleY;
     }
     }
 }
 }
 
 
@@ -213,26 +487,82 @@ void TextSprite::sceneRender( const SceneRenderState* pSceneRenderState, const S
 
 
 void TextSprite::RenderLetter(BatchRender* pBatchRenderer, Vector2& cursor, U32 charID, F32 ratio)
 void TextSprite::RenderLetter(BatchRender* pBatchRenderer, Vector2& cursor, U32 charID, F32 ratio)
 {
 {
-   const BitmapFontCharacter bmChar = mFontAsset->mBitmapFont.getCharacter(charID);
-   cursor.x -= (bmChar.mXOffset * ratio);
-
-   Vector2 left = (mRenderOOBB[1] - mRenderOOBB[0]);
-   left.Normalize((F32)cursor.x + (bmChar.mXOffset * ratio));
-
-   Vector2 right = (mRenderOOBB[1] - mRenderOOBB[0]);
-   right.Normalize(bmChar.mWidth * ratio);
-
-   Vector2 top = (mRenderOOBB[3] - mRenderOOBB[0]);
-   top.Normalize((F32)cursor.y - (mFontAsset->mBitmapFont.mBaseline * ratio) + (bmChar.mYOffset * ratio));
-
-   Vector2 bottom = (mRenderOOBB[3] - mRenderOOBB[0]);
-   bottom.Normalize(bmChar.mHeight * ratio);
+   const BitmapFontCharacter& bmChar = mFontAsset->mBitmapFont.getCharacter(charID);
+
+   //inset, for hiding part of a letter
+   F32 insetLeft, insetRight, insetTop, insetBottom;
+   insetLeft = 0;
+   insetRight = 0;
+   insetTop = 0;
+   insetBottom = 0;
+
+   // Cropping time!
+   if (mOverflowX == OVERFLOW_X_HIDDEN) 
+   {
+      if ((cursor.x + (bmChar.mWidth * ratio * mFontScaleX) <= 0) || (cursor.x >= mSize.x))
+         return;
+
+      if (cursor.x < 0 && (cursor.x + (bmChar.mWidth * ratio * mFontScaleX) > 0))
+      {
+         insetLeft = -(cursor.x / (bmChar.mWidth * ratio * mFontScaleX));
+      }
+
+      if (cursor.x < mSize.x && (cursor.x + (bmChar.mWidth * ratio * mFontScaleX) > mSize.x))
+      {
+         insetRight = (((cursor.x + (bmChar.mWidth * ratio * mFontScaleX)) - mSize.x) / (bmChar.mWidth * ratio * mFontScaleX));
+      }
+
+      if (insetLeft + insetRight > 1)
+         return;
+   }
+   if (mOverflowY == OVERFLOW_Y_HIDDEN)
+   {
+      F32 tempTop, tempBottom;
+      tempTop = cursor.y - (mFontAsset->mBitmapFont.mBaseline * ratio * mFontScaleY);
+      tempBottom = tempTop + (bmChar.mHeight * ratio * mFontScaleY);
+
+      if ((tempBottom <= 0) || (tempTop >= mSize.y))
+         return;
+
+      if (tempTop < 0 && tempBottom > 0)
+      {
+         insetTop = -(tempTop / (bmChar.mHeight * ratio * mFontScaleY));
+      }
+
+      if (tempTop < mSize.y && tempBottom > mSize.y)
+      {
+         insetBottom = (tempBottom - mSize.y) / (bmChar.mHeight * ratio * mFontScaleY);
+      }
+
+      if (insetTop + insetBottom > 1)
+         return;
+   }
+
+   //create the source rect
+   Vector2 sourceOOBB[4];
+   sourceOOBB[0].Set(bmChar.mOOBB[0].x + ((insetLeft * (F32)bmChar.mWidth) / (F32)bmChar.mPageWidth), bmChar.mOOBB[0].y - ((insetBottom * (F32)bmChar.mHeight) / (F32)bmChar.mPageHeight));
+   sourceOOBB[1].Set(bmChar.mOOBB[1].x - ((insetRight * (F32)bmChar.mWidth) / (F32)bmChar.mPageWidth), bmChar.mOOBB[1].y - ((insetBottom * (F32)bmChar.mHeight) / (F32)bmChar.mPageHeight));
+   sourceOOBB[2].Set(bmChar.mOOBB[2].x - ((insetRight * (F32)bmChar.mWidth) / (F32)bmChar.mPageWidth), bmChar.mOOBB[2].y + ((insetTop * (F32)bmChar.mHeight) / (F32)bmChar.mPageHeight));
+   sourceOOBB[3].Set(bmChar.mOOBB[3].x + ((insetLeft * (F32)bmChar.mWidth) / (F32)bmChar.mPageWidth), bmChar.mOOBB[3].y + ((insetTop * (F32)bmChar.mHeight) / (F32)bmChar.mPageHeight));
+
+   //create the destination rect
+   Vector2 destLeft = (mRenderOOBB[1] - mRenderOOBB[0]);
+   destLeft.Normalize((F32)cursor.x + (insetLeft * bmChar.mWidth * ratio * mFontScaleX));
+
+   Vector2 destWidth = (mRenderOOBB[1] - mRenderOOBB[0]);
+   destWidth.Normalize(((bmChar.mWidth * ratio) - (insetLeft * (bmChar.mWidth * ratio)) - (insetRight * (bmChar.mWidth * ratio))) * mFontScaleX);
+
+   Vector2 destTop = -(mRenderOOBB[3] - mRenderOOBB[0]);
+   destTop.Normalize((F32)cursor.y - (((mFontAsset->mBitmapFont.mBaseline * ratio) - (bmChar.mYOffset * ratio) - (insetTop * bmChar.mHeight * ratio)) * mFontScaleY));
+
+   Vector2 destHeight = -(mRenderOOBB[3] - mRenderOOBB[0]);
+   destHeight.Normalize(((bmChar.mHeight * ratio) - (insetBottom * bmChar.mHeight * ratio) - (insetTop * bmChar.mHeight * ratio)) * mFontScaleY);
 
 
    Vector2 destOOBB[4];
    Vector2 destOOBB[4];
-   destOOBB[0] = (mRenderOOBB[3] + left - top - bottom);
-   destOOBB[1] = (mRenderOOBB[3] + left + right - top - bottom);
-   destOOBB[2] = (mRenderOOBB[3] + left + right - top);
-   destOOBB[3] = (mRenderOOBB[3] + left - top);
+   destOOBB[0] = (mRenderOOBB[3] + destLeft + destTop + destHeight);
+   destOOBB[1] = (mRenderOOBB[3] + destLeft + destWidth + destTop + destHeight);
+   destOOBB[2] = (mRenderOOBB[3] + destLeft + destWidth + destTop);
+   destOOBB[3] = (mRenderOOBB[3] + destLeft + destTop);
 
 
    // Submit batched quad.
    // Submit batched quad.
    pBatchRenderer->SubmitQuad(
    pBatchRenderer->SubmitQuad(
@@ -240,13 +570,156 @@ void TextSprite::RenderLetter(BatchRender* pBatchRenderer, Vector2& cursor, U32
       destOOBB[1],
       destOOBB[1],
       destOOBB[2],
       destOOBB[2],
       destOOBB[3],
       destOOBB[3],
-      bmChar.mOOBB[0],
-      bmChar.mOOBB[1],
-      bmChar.mOOBB[2],
-      bmChar.mOOBB[3],
+      sourceOOBB[0],
+      sourceOOBB[1],
+      sourceOOBB[2],
+      sourceOOBB[3],
       mFontAsset->getImageTexture(bmChar.mPage));
       mFontAsset->getImageTexture(bmChar.mPage));
+}
 
 
-   cursor.x += (bmChar.mXAdvance * ratio);
+//-----------------------------------------------------------------------------
+
+void TextSprite::CalculateSpatials(F32 ratio)
+{
+   F32 length = 0;
+   S32 start = -1;
+   S32 wordEnd = 0;
+   F32 wordEndLength = 0;
+   S32 prevCharID = -1;
+   mLine.clear();
+   const U32 renderCharacters = mText.length();
+
+   for (U32 i = 0; i < renderCharacters; i++)
+   {
+      U32 charID = mText.getChar(i);
+      const BitmapFontCharacter& bmChar = mFontAsset->mBitmapFont.getCharacter(charID);
+
+      if (start == -1 && charID != 32)
+      {
+         start = i;
+         length = 0;
+         mLine.push_back(BitmapFontLineInfo(start));
+      }
+
+      if (i == start)
+      {
+         length -= (bmChar.mXOffset * ratio * mFontScaleX);
+      }
+
+      length += getCursorAdvance(bmChar, prevCharID, ratio);
+
+      if (mOverflowX == OVERFLOW_X_WRAP)
+      {
+         if (prevCharID != 32 && prevCharID != -1 && charID == 32)
+         {
+            wordEnd = i - 1;
+            wordEndLength = length - getCursorAdvance(bmChar, prevCharID, ratio);
+         }
+
+         if (length > mSize.x && wordEnd > start)
+         {
+            mLine.back().mEnd = wordEnd;
+            U32 endCharID = mText.getChar(wordEnd);
+            const BitmapFontCharacter& bmCharEnd = mFontAsset->mBitmapFont.getCharacter(endCharID);
+            i = wordEnd;
+
+            start = -1;
+            length = 0;
+
+            S32 prevEndCharID = -1;
+            if (wordEnd != 0)
+            {
+               prevEndCharID = mText.getChar(wordEnd - 1);
+            }
+
+            wordEndLength += -getCursorAdvance(bmCharEnd, prevEndCharID, ratio) + (bmCharEnd.mWidth * ratio * mFontScaleX) + (bmCharEnd.mXOffset * ratio * mFontScaleX);
+            mLine.back().mLength = wordEndLength;
+         }
+      }
+
+      prevCharID = charID;
+
+      if ((i + 1) == renderCharacters)
+      {
+         if (charID != 32)//this is the last character and if it's not a space then it's the end of a word.
+         {
+            wordEndLength = length;
+            wordEnd = i;
+         }
+         mLine.back().mEnd = wordEnd;
+         U32 endCharID = mText.getChar(wordEnd);
+         const BitmapFontCharacter& bmCharEnd = mFontAsset->mBitmapFont.getCharacter(endCharID);
+
+         S32 prevEndCharID = -1;
+         if (wordEnd != 0)
+         {
+            prevEndCharID = mText.getChar(wordEnd - 1);
+         }
+
+         wordEndLength += -getCursorAdvance(bmCharEnd, prevEndCharID, ratio) + (bmCharEnd.mWidth * ratio * mFontScaleX) + (bmCharEnd.mXOffset * ratio * mFontScaleX);
+         mLine.back().mLength = wordEndLength;
+      }
+   }
+
+   mFontSpatialsDirty = false;
+   mCalculatedSize = mSize;
+}
+
+//-----------------------------------------------------------------------------
+
+void TextSprite::ApplyAlignment(Vector2& cursor, U32 totalRows, U32 row, F32 length, U32 charCount, F32 ratio)
+{
+   //Horizontal Align
+   if (mTextAlign == ALIGN_CENTER)
+   {
+      cursor.x += ((mSize.x - length) / 2.0f);
+   }
+   else if (mTextAlign == ALIGN_RIGHT)
+   {
+      cursor.x += (mSize.x - length);
+   }
+   else if (mTextAlign == ALIGN_JUSTIFY)
+   {
+      U32 gapCount = charCount - 1;
+      mKerning = (-(mSize.x - length) / gapCount) / mFontScaleX;
+   }
+
+   //Vertical Align
+   const F32 lineHeight = GetLineHeight();
+   if (mTextVAlign == VALIGN_TOP)
+   {
+      cursor.y = ((mFontAsset->mBitmapFont.mBaseline * ratio) + (lineHeight * row)) * mFontScaleY;
+   }
+   else if (mTextVAlign == VALIGN_MIDDLE)
+   {
+      cursor.y = (mSize.y / 2.0f) - ((((lineHeight / 2.0f) * totalRows) - (lineHeight * row) - (mFontAsset->mBitmapFont.mBaseline * ratio)) * mFontScaleY);
+   }
+   else if (mTextVAlign == VALIGN_BOTTOM)
+   {
+      cursor.y = mSize.y - (((lineHeight * totalRows) - (lineHeight * row) - (mFontAsset->mBitmapFont.mBaseline * ratio)) * mFontScaleY);
+   }
+}
+
+
+//-----------------------------------------------------------------------------
+
+F32 TextSprite::getCursorAdvance(U32 charID, S32 prevCharID, F32 ratio)
+{
+   const BitmapFontCharacter& bmChar = mFontAsset->mBitmapFont.getCharacter(charID);
+   return getCursorAdvance(bmChar, prevCharID, ratio);
+}
+
+F32 TextSprite::getCursorAdvance(const BitmapFontCharacter& bmChar, S32 prevCharID, F32 ratio)
+{
+   if (prevCharID != -1)
+   {
+      S16 kerning = mFontAsset->mBitmapFont.getKerning(prevCharID, bmChar.mCharID);
+      return (((bmChar.mXAdvance - kerning) * ratio) - mKerning) * mFontScaleX;
+   }
+   else
+   {
+      return ((bmChar.mXAdvance * ratio) - mKerning) * mFontScaleX;
+   }
 }
 }
 
 
 
 
@@ -260,14 +733,9 @@ bool TextSprite::setFont( const char* pFontAssetId )
     // Finish if no font asset.
     // Finish if no font asset.
     if ( mFontAsset.isNull() )
     if ( mFontAsset.isNull() )
         return false;
         return false;
+
+    mFontSpatialsDirty = true;
     
     
     // Return Okay.
     // Return Okay.
     return true;
     return true;
 }
 }
-
-//-----------------------------------------------------------------------------
-
-bool TextSprite::setTextAlignment( void* obj, const char* data )
-{
-    static_cast<TextSprite*>( obj )->setTextAlignment( getTextAlignmentEnum(data) ); return false;
-}

+ 54 - 17
engine/source/2d/sceneobject/TextSprite.h

@@ -43,6 +43,10 @@
 #include "2d/core/utility.h"
 #include "2d/core/utility.h"
 #endif
 #endif
 
 
+#ifndef _BITMAP_FONT_LINE_INFO_H_
+#include "bitmapFont/BitmapFontLineInfo.h"
+#endif
+
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 class TextSprite : public SceneObject
 class TextSprite : public SceneObject
@@ -74,7 +78,7 @@ public:
        INVALID_OVERFLOW_X,
        INVALID_OVERFLOW_X,
 
 
        OVERFLOW_X_WRAP,
        OVERFLOW_X_WRAP,
-       OVERFLOW_X_EXPAND,
+       OVERFLOW_X_VISIBLE,
        OVERFLOW_X_HIDDEN,
        OVERFLOW_X_HIDDEN,
        OVERFLOW_X_SHRINK,
        OVERFLOW_X_SHRINK,
     };
     };
@@ -83,7 +87,7 @@ public:
     {
     {
        INVALID_OVERFLOW_Y,
        INVALID_OVERFLOW_Y,
 
 
-       OVERFLOW_Y_EXPAND,
+       OVERFLOW_Y_VISIBLE,
        OVERFLOW_Y_HIDDEN,
        OVERFLOW_Y_HIDDEN,
        OVERFLOW_Y_SHRINK,
        OVERFLOW_Y_SHRINK,
     };
     };
@@ -102,6 +106,11 @@ private:
     F32                     mCustomLineHeight;
     F32                     mCustomLineHeight;
     F32                     mKerning;
     F32                     mKerning;
 
 
+    std::vector<BitmapFontLineInfo> mLine;
+    bool                    mFontSpatialsDirty;
+    Vector2                 mCalculatedSize;
+
+
 public:
 public:
     TextSprite();
     TextSprite();
     ~TextSprite();
     ~TextSprite();
@@ -120,41 +129,41 @@ public:
 
 
     bool setFont( const char* pFontAssetId );
     bool setFont( const char* pFontAssetId );
     const char* getFont(void) const                                         { return mFontAsset.getAssetId(); }
     const char* getFont(void) const                                         { return mFontAsset.getAssetId(); }
-    inline void setText(const StringBuffer& text)                           { mText.set(&text); }
+    inline void setText(const StringBuffer& text)                           { mText.set(&text); mFontSpatialsDirty = true; }
     inline StringBuffer& getText(void)                                      { return mText; }
     inline StringBuffer& getText(void)                                      { return mText; }
-    inline void setFontSize(const F32 size)                                 { mFontSize = size; }
+    inline void setFontSize(const F32 size)                                 { mFontSize = size; mFontSpatialsDirty = true; }
     inline F32 getFontSize(void) const                                      { return mFontSize; }
     inline F32 getFontSize(void) const                                      { return mFontSize; }
-    inline void setFontScaleX(const F32 scale)                              { mFontScaleX = scale; }
+    inline void setFontScaleX(const F32 scale)                              { mFontScaleX = scale; mFontSpatialsDirty = true; }
     inline F32 getFontScaleX(void) const                                    { return mFontScaleX; }
     inline F32 getFontScaleX(void) const                                    { return mFontScaleX; }
-    inline void setFontScaleY(const F32 scale)                              { mFontScaleY = scale; }
+    inline void setFontScaleY(const F32 scale)                              { mFontScaleY = scale; mFontSpatialsDirty = true; }
     inline F32 getFontScaleY(void) const                                    { return mFontScaleY; }
     inline F32 getFontScaleY(void) const                                    { return mFontScaleY; }
 
 
-    inline void setTextAlignment(const TextAlign alignment)                 { mTextAlign = alignment; }
+    inline void setTextAlignment(const TextAlign alignment)                 { mTextAlign = alignment; mFontSpatialsDirty = true; }
     inline TextAlign getTextAlignment(void) const                           { return mTextAlign; }
     inline TextAlign getTextAlignment(void) const                           { return mTextAlign; }
     static TextAlign getTextAlignmentEnum(const char* label);
     static TextAlign getTextAlignmentEnum(const char* label);
     static const char* getTextAlignmentDescription(const TextAlign alignment);
     static const char* getTextAlignmentDescription(const TextAlign alignment);
 
 
-    inline void setTextVAlignment(const TextVAlign alignment)               { mTextVAlign = alignment; }
+    inline void setTextVAlignment(const TextVAlign alignment)               { mTextVAlign = alignment; mFontSpatialsDirty = true; }
     inline TextVAlign getTextVAlignment(void) const                         { return mTextVAlign; }
     inline TextVAlign getTextVAlignment(void) const                         { return mTextVAlign; }
     static TextVAlign getTextVAlignmentEnum(const char* label);
     static TextVAlign getTextVAlignmentEnum(const char* label);
     static const char* getTextVAlignmentDescription(const TextVAlign alignment);
     static const char* getTextVAlignmentDescription(const TextVAlign alignment);
 
 
-    inline void setOverflowModeX(const OverflowModeX mode)                  { mOverflowX = mode; }
+    inline void setOverflowModeX(const OverflowModeX mode)                  { mOverflowX = mode; mFontSpatialsDirty = true; }
     inline OverflowModeX getOverflowModeX(void) const                       { return mOverflowX; }
     inline OverflowModeX getOverflowModeX(void) const                       { return mOverflowX; }
     static OverflowModeX getOverflowModeXEnum(const char* label);
     static OverflowModeX getOverflowModeXEnum(const char* label);
     static const char* getOverflowModeXDescription(const OverflowModeX mode);
     static const char* getOverflowModeXDescription(const OverflowModeX mode);
 
 
-    inline void setOverflowModeY(const OverflowModeY mode)                  { mOverflowY = mode; }
+    inline void setOverflowModeY(const OverflowModeY mode)                  { mOverflowY = mode; mFontSpatialsDirty = true; }
     inline OverflowModeY getOverflowModeY(void) const                       { return mOverflowY; }
     inline OverflowModeY getOverflowModeY(void) const                       { return mOverflowY; }
     static OverflowModeY getOverflowModeYEnum(const char* label);
     static OverflowModeY getOverflowModeYEnum(const char* label);
     static const char* getOverflowModeYDescription(const OverflowModeY mode);
     static const char* getOverflowModeYDescription(const OverflowModeY mode);
 
 
-    inline void setAutoLineHeight(const bool isAuto)                        { mAutoLineHeight = isAuto; }
+    inline void setAutoLineHeight(const bool isAuto)                        { mAutoLineHeight = isAuto; mFontSpatialsDirty = true; }
     inline bool getAutoLineHeight(void) const                               { return mAutoLineHeight; }
     inline bool getAutoLineHeight(void) const                               { return mAutoLineHeight; }
-    inline void setCustomLineHeight(const F32 lineHeight)                   { mCustomLineHeight = lineHeight; }
+    inline void setCustomLineHeight(const F32 lineHeight)                   { mCustomLineHeight = lineHeight; mFontSpatialsDirty = true; }
     inline F32 getCustomLineHeight(void) const                              { return mCustomLineHeight; }
     inline F32 getCustomLineHeight(void) const                              { return mCustomLineHeight; }
 
 
-    inline void setKerning(const F32 kern)                                  { mKerning = kern; }
+    inline void setKerning(const F32 kern)                                  { mKerning = kern; mFontSpatialsDirty = true; }
     inline F32 getKerning(void) const                                       { return mKerning; }
     inline F32 getKerning(void) const                                       { return mKerning; }
 
 
     // Declare Console Object.
     // Declare Console Object.
@@ -167,16 +176,44 @@ protected:
 
 
     static bool setText( void* obj, const char* data )                      { static_cast<TextSprite*>( obj )->setText( data ); return false; }
     static bool setText( void* obj, const char* data )                      { static_cast<TextSprite*>( obj )->setText( data ); return false; }
     static const char* getText( void* obj, const char* data )               { return static_cast<TextSprite*>( obj )->getText().getPtr8(); }
     static const char* getText( void* obj, const char* data )               { return static_cast<TextSprite*>( obj )->getText().getPtr8(); }
-    static bool writeText( void* obj, StringTableEntry pFieldName )         { return static_cast<TextSprite*>(obj)->mText.length() != 0; }
+    static bool writeText(void* obj, StringTableEntry pFieldName)         { return static_cast<TextSprite*>(obj)->mText.length() != 0; }
 
 
-    static bool setFontSize(void* obj, const char* data)                    { static_cast<TextSprite*>(obj)->setFontSize( dAtof(data) ); return false; }
+    static bool setFontSize(void* obj, const char* data)                    { static_cast<TextSprite*>(obj)->setFontSize(dAtof(data)); return false; }
     static bool writeFontSize(void* obj, StringTableEntry pFieldName)       { return static_cast<TextSprite*>(obj)->getFontSize() != 1.0f; }
     static bool writeFontSize(void* obj, StringTableEntry pFieldName)       { return static_cast<TextSprite*>(obj)->getFontSize() != 1.0f; }
 
 
-    static bool setTextAlignment( void* obj, const char* data );
-    static bool writeTextAlignment( void* obj, StringTableEntry pFieldName ){return static_cast<TextSprite*>(obj)->getTextAlignment() != TextSprite::ALIGN_CENTER; }
+    static bool setFontScaleX(void* obj, const char* data)                    { static_cast<TextSprite*>(obj)->setFontScaleX(dAtof(data)); return false; }
+    static bool writeFontScaleX(void* obj, StringTableEntry pFieldName)       { return static_cast<TextSprite*>(obj)->getFontScaleX() != 1.0f; }
+
+    static bool setFontScaleY(void* obj, const char* data)                    { static_cast<TextSprite*>(obj)->setFontScaleY(dAtof(data)); return false; }
+    static bool writeFontScaleY(void* obj, StringTableEntry pFieldName)       { return static_cast<TextSprite*>(obj)->getFontScaleY() != 1.0f; }
+
+    static bool setTextAlignment(void* obj, const char* data);
+    static bool writeTextAlignment(void* obj, StringTableEntry pFieldName){ return static_cast<TextSprite*>(obj)->getTextAlignment() != TextSprite::ALIGN_LEFT; }
+
+    static bool setTextVAlignment(void* obj, const char* data);
+    static bool writeTextVAlignment(void* obj, StringTableEntry pFieldName){ return static_cast<TextSprite*>(obj)->getTextVAlignment() != TextSprite::VALIGN_TOP; }
+
+    static bool setOverflowModeX(void* obj, const char* data);
+    static bool writeOverflowModeX(void* obj, StringTableEntry pFieldName){ return static_cast<TextSprite*>(obj)->getOverflowModeX() != TextSprite::OVERFLOW_X_WRAP; }
+
+    static bool setOverflowModeY(void* obj, const char* data);
+    static bool writeOverflowModeY(void* obj, StringTableEntry pFieldName){ return static_cast<TextSprite*>(obj)->getOverflowModeY() != TextSprite::OVERFLOW_Y_HIDDEN; }
+
+    static bool writeAutoLineHeight(void* obj, StringTableEntry pFieldName)       { return static_cast<TextSprite*>(obj)->getAutoLineHeight() != true; }
+
+    static bool setCustomLineHeight(void* obj, const char* data)                    { static_cast<TextSprite*>(obj)->setCustomLineHeight(dAtof(data)); return false; }
+    static bool writeCustomLineHeight(void* obj, StringTableEntry pFieldName)       { return static_cast<TextSprite*>(obj)->getCustomLineHeight() != 1.0f; }
+
+    static bool setKerning(void* obj, const char* data)                    { static_cast<TextSprite*>(obj)->setKerning(dAtof(data)); return false; }
+    static bool writeKerning(void* obj, StringTableEntry pFieldName)       { return static_cast<TextSprite*>(obj)->getKerning() != 0.0f; }
 
 
 private:
 private:
    void RenderLetter(BatchRender* pBatchRenderer, Vector2& cursor, U32 charID, F32 ratio);
    void RenderLetter(BatchRender* pBatchRenderer, Vector2& cursor, U32 charID, F32 ratio);
+   void TextSprite::ApplyAlignment(Vector2& cursor, U32 totalRows, U32 row, F32 length, U32 charCount, F32 ratio);
+   F32 TextSprite::getCursorAdvance(U32 charID, S32 prevCharID, F32 ratio);
+   F32 TextSprite::getCursorAdvance(const BitmapFontCharacter& bmChar, S32 prevCharID, F32 ratio);
+   F32 GetLineHeight() { return (mAutoLineHeight) ? mFontSize : mCustomLineHeight; }
+   void TextSprite::CalculateSpatials(F32 ratio);
 };
 };
 
 
 #endif // _TEXT_SPRITE_H_
 #endif // _TEXT_SPRITE_H_

+ 181 - 46
engine/source/2d/sceneobject/TextSprite_ScriptBinding.h

@@ -23,29 +23,27 @@
 ConsoleMethodGroupBeginWithDocs(TextSprite, SceneObject)
 ConsoleMethodGroupBeginWithDocs(TextSprite, SceneObject)
 
 
 /*! Sets the image asset to use..
 /*! Sets the image asset to use..
-    @param imageName The image asset to use.
+    @param fontName The font asset to use.
     @return Returns true on success.
     @return Returns true on success.
 */
 */
 ConsoleMethodWithDocs(TextSprite, setFont, ConsoleBool, 3, 3, (fontAssetId))
 ConsoleMethodWithDocs(TextSprite, setFont, ConsoleBool, 3, 3, (fontAssetId))
 {
 {
-    // Set Image.
     return object->setFont( argv[2] );
     return object->setFont( argv[2] );
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-/*! Gets current image asset..
-    @return The current image asset.
+/*! Gets current font asset..
+    @return The current font asset.
 */
 */
 ConsoleMethodWithDocs(TextSprite, getFont, ConsoleString, 2, 2, ())
 ConsoleMethodWithDocs(TextSprite, getFont, ConsoleString, 2, 2, ())
 {
 {
-    // Get Image.
     return object->getFont();
     return object->getFont();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-/*! Set the text to render.
+/*! Sets the text to render.
 */
 */
 ConsoleMethodWithDocs(TextSprite, setText, ConsoleVoid, 3, 3, (text))
 ConsoleMethodWithDocs(TextSprite, setText, ConsoleVoid, 3, 3, (text))
 {
 {
@@ -63,76 +61,213 @@ ConsoleMethodWithDocs(TextSprite, getText, ConsoleString, 2, 2, ())
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-/*! Set the text alignment to 'left', 'center' or 'right'.
-    @param alignment The text alignment of 'left', 'center' or 'right'.
+/*! Sets the size of the font.
+@param size The distance between the top of a line of text and the bottom.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setFontSize, ConsoleVoid, 3, 3, (size))
+{
+   object->setFontSize(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the size of the font.
+@return The size of the font.
+*/
+ConsoleMethodWithDocs(TextSprite, getFontSize, ConsoleFloat, 2, 2, ())
+{
+   return object->getFontSize();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the scale of the font in the X direction.
+@param scale The amount to multiply the width of the text by.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setFontScaleX, ConsoleVoid, 3, 3, (scale))
+{
+   object->setFontScaleX(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the scale of the font in the X direction.
+@return The scale of the of the font in the X direction.
+*/
+ConsoleMethodWithDocs(TextSprite, getFontScaleX, ConsoleFloat, 2, 2, ())
+{
+   return object->getFontScaleX();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the scale of the font in the Y direction.
+@param scale The amount to multiply the height of the text by.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setFontScaleY, ConsoleVoid, 3, 3, (scale))
+{
+   object->setFontScaleY(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the scale of the font in the Y direction.
+@return The scale of the of the font in the Y direction.
+*/
+ConsoleMethodWithDocs(TextSprite, getFontScaleY, ConsoleFloat, 2, 2, ())
+{
+   return object->getFontScaleY();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the horizontal text alignment to 'left', 'center', 'right', or 'justify'.
+    @param alignment The text alignment of 'left', 'center', 'right', or 'justify'.
     @return No return value.
     @return No return value.
 */
 */
 ConsoleMethodWithDocs(TextSprite, setTextAlignment, ConsoleVoid, 3, 3, (alignment))
 ConsoleMethodWithDocs(TextSprite, setTextAlignment, ConsoleVoid, 3, 3, (alignment))
 {
 {
-
     object->setTextAlignment( TextSprite::getTextAlignmentEnum(argv[2]) );
     object->setTextAlignment( TextSprite::getTextAlignmentEnum(argv[2]) );
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-/*! Gets the text alignment.
-    @return The text alignment of 'left', 'center' or 'right'.
+/*! Gets the horizontal text alignment.
+    @return The text alignment of 'left', 'center', 'right', or 'justify'.
 */
 */
 ConsoleMethodWithDocs(TextSprite, getTextAlignment, ConsoleString, 2, 2, ())
 ConsoleMethodWithDocs(TextSprite, getTextAlignment, ConsoleString, 2, 2, ())
 {
 {
-    return TextSprite::getTextAlignmentDescription(object->getTextAlignment());
+   return TextSprite::getTextAlignmentDescription(object->getTextAlignment());
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-/*! Set the size of the font characters.
-    @param width The width of a font character.
-    @param height The height of a font character.
-    @return No return value.
+/*! Sets the vertical text alignment to 'top', 'middle', or 'bottom'.
+@param alignment The vertical text alignment of 'top', 'middle', or 'bottom'.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setTextVAlignment, ConsoleVoid, 3, 3, (alignment))
+{
+   object->setTextVAlignment(TextSprite::getTextVAlignmentEnum(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the vertical text alignment.
+@return The vertical text alignment of 'top', 'middle', or 'bottom'.
+*/
+ConsoleMethodWithDocs(TextSprite, getTextVAlignment, ConsoleString, 2, 2, ())
+{
+   return TextSprite::getTextVAlignmentDescription(object->getTextVAlignment());
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the overflow mode X to 'wrap', 'visible', 'hidden', or 'shrink'.
+@param mode The overflow mode X of 'wrap', 'visible', 'hidden', or 'shrink'.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setOverflowModeX, ConsoleVoid, 3, 3, (mode))
+{
+   object->setOverflowModeX(TextSprite::getOverflowModeXEnum(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the overflow mode X.
+@return The overflow mode X of 'wrap', 'visible', 'hidden', or 'shrink'.
 */
 */
-ConsoleMethodWithDocs(TextSprite, setFontSize, ConsoleVoid, 3, 4, (width, height))
+ConsoleMethodWithDocs(TextSprite, getOverflowModeX, ConsoleString, 2, 2, ())
 {
 {
-    F32 width, height;
+   return TextSprite::getOverflowModeXDescription(object->getOverflowModeX());
+}
 
 
-    U32 elementCount = Utility::mGetStringElementCount(argv[2]);
+//-----------------------------------------------------------------------------
 
 
-    // ("width height")
-    if ((elementCount == 2) && (argc == 3))
-    {
-        width = dAtof(Utility::mGetStringElement(argv[2], 0));
-        height = dAtof(Utility::mGetStringElement(argv[2], 1));
-    }
+/*! Sets the overflow mode Y to 'visible', 'hidden', or 'shrink'.
+@param mode The overflow mode Y of 'visible', 'hidden', or 'shrink'.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setOverflowModeY, ConsoleVoid, 3, 3, (mode))
+{
+   object->setOverflowModeY(TextSprite::getOverflowModeYEnum(argv[2]));
+}
 
 
-    // (width, [height])
-    else if (elementCount == 1)
-    {
-        width = dAtof(argv[2]);
+//-----------------------------------------------------------------------------
 
 
-        if (argc > 3)
-            height = dAtof(argv[3]);
-        else
-            height = width;
-    }
-    // Invalid
-    else
-    {
-        Con::warnf("TextSprite::setFontSize() - Invalid number of parameters!");
-        return;
-    }
+/*! Gets the overflow mode Y.
+@return The overflow mode Y of 'visible', 'hidden', or 'shrink'.
+*/
+ConsoleMethodWithDocs(TextSprite, getOverflowModeY, ConsoleString, 2, 2, ())
+{
+   return TextSprite::getOverflowModeYDescription(object->getOverflowModeY());
+}
 
 
-    // Set character size.
-    object->setFontSize(width);
+//-----------------------------------------------------------------------------
 
 
+/*! Sets if the line height should be automatically calculated.
+@param isAuto True if the line height automatically calculated or false to use the custom line height.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setAutoLineHeight, ConsoleVoid, 3, 3, (isAuto))
+{
+   object->setAutoLineHeight(dAtob(argv[2]));
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-/*! Gets the size of the font characters.
-    @return The size of the font characters.
+/*! Gets whether the line height is automatically calculated.
+@return True if the line height is automatically calculated or false if the custom line height is used.
 */
 */
-ConsoleMethodWithDocs(TextSprite, getFontSize, ConsoleFloat, 2, 2, ())
+ConsoleMethodWithDocs(TextSprite, getAutoLineHeight, ConsoleBool, 2, 2, ())
+{
+   return object->getAutoLineHeight();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the custom line height and disables the auto line height.
+@param lineHeight The distance between the top and the bottom of a line before adjusting by the fontScaleY.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setCustomLineHeight, ConsoleVoid, 3, 3, (lineHeight))
+{
+   object->setCustomLineHeight(dAtof(argv[2]));
+   object->setAutoLineHeight(false);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the custom line height.
+@return The distance between the top and the bottom of a line.
+*/
+ConsoleMethodWithDocs(TextSprite, getCustomLineHeight, ConsoleFloat, 2, 2, ())
+{
+   return object->getCustomLineHeight();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets kerning to be used between each character. Kerning is ignored when using alignment of 'justify'.
+@param kerning The amount to decrease the distance by between each character. Positive valus move the characters closer together and negative values move them apart.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setKerning, ConsoleVoid, 3, 3, (kerning))
+{
+   object->setKerning(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the kerning amount.
+@return The amount each character is moved closer together.
+*/
+ConsoleMethodWithDocs(TextSprite, getKerning, ConsoleFloat, 2, 2, ())
 {
 {
-    return object->getFontSize();
+   return object->getKerning();
 }
 }
 
 
 ConsoleMethodGroupEndWithDocs(TextSprite)
 ConsoleMethodGroupEndWithDocs(TextSprite)

+ 1 - 0
engine/source/bitmapFont/BitmapFont.cc

@@ -186,6 +186,7 @@ namespace font
                   ci.mPage = S32(dAtoi(Value));
                   ci.mPage = S32(dAtoi(Value));
                currentWordCount++;
                currentWordCount++;
             }
             }
+            ci.mCharID = CharID;
             ci.ProcessCharacter(mWidth, mHeight);
             ci.ProcessCharacter(mWidth, mHeight);
             mChar.emplace(CharID, ci);
             mChar.emplace(CharID, ci);
          }
          }

+ 3 - 2
engine/source/bitmapFont/BitmapFont.h

@@ -63,8 +63,9 @@ namespace font
       BitmapFont();
       BitmapFont();
       bool parseFont(Stream& io_rStream);
       bool parseFont(Stream& io_rStream);
       TextureHandle LoadTexture(StringTableEntry fileName);
       TextureHandle LoadTexture(StringTableEntry fileName);
-      const BitmapFontCharacter getCharacter(const U16 charID) { return mChar[charID]; }
-      inline const F32 getSizeRatio(const U16 size) { return (F32)size / mLineHeight; }
+      const BitmapFontCharacter& getCharacter(const U16 charID) { return mChar[charID]; }
+      inline const F32 getSizeRatio(const F32 size) { return size / mLineHeight; }
+      inline const S16 getKerning(U16 first, U16 second) { return (S16)mKerning[make_pair(first, second)]; }
 
 
    private:
    private:
       inline void AddKerning(U16 first, U16 second, S16 amount) { mKerning[make_pair(first, second)] = amount; }
       inline void AddKerning(U16 first, U16 second, S16 amount) { mKerning[make_pair(first, second)] = amount; }

+ 2 - 0
engine/source/bitmapFont/BitmapFontCharacter.cc

@@ -40,5 +40,7 @@ namespace font
       mOOBB[1] = Vector2(right, top);
       mOOBB[1] = Vector2(right, top);
       mOOBB[2] = Vector2(right, bottom);
       mOOBB[2] = Vector2(right, bottom);
       mOOBB[3] = Vector2(left, bottom);
       mOOBB[3] = Vector2(left, bottom);
+      mPageWidth = width;
+      mPageHeight = height;
    }
    }
 }
 }

+ 2 - 0
engine/source/bitmapFont/BitmapFontCharacter.h

@@ -36,11 +36,13 @@ namespace font
    class BitmapFontCharacter
    class BitmapFontCharacter
    {
    {
    public:
    public:
+      U16 mCharID;
       U16 mX, mY;
       U16 mX, mY;
       U16 mWidth, mHeight;
       U16 mWidth, mHeight;
       F32 mXOffset, mYOffset;
       F32 mXOffset, mYOffset;
       F32 mXAdvance;
       F32 mXAdvance;
       U16 mPage;
       U16 mPage;
+      U16 mPageWidth, mPageHeight;
       Vector2 mOOBB[4];
       Vector2 mOOBB[4];
 
 
       BitmapFontCharacter() : mX(0), mY(0), mWidth(0), mHeight(0), mXOffset(0), mYOffset(0), mXAdvance(0), mPage(0)
       BitmapFontCharacter() : mX(0), mY(0), mWidth(0), mHeight(0), mXOffset(0), mYOffset(0), mXAdvance(0), mPage(0)

+ 0 - 0
engine/source/bitmapFont/BitmapFontCharacterInfo.h


+ 51 - 0
engine/source/bitmapFont/BitmapFontLineInfo.h

@@ -0,0 +1,51 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _BITMAP_FONT_LINE_INFO_H_
+#define _BITMAP_FONT_LINE_INFO_H_
+
+#ifndef _UTILITY_H_
+#include "2d/core/utility.h"
+#endif
+
+namespace font
+{
+   struct BitmapFontLineInfo
+   {
+   public:
+      U32 mStart;
+      U32 mEnd;
+      F32 mLength;
+
+      BitmapFontLineInfo() : mStart(0), mEnd(0), mLength(0.0f)
+      {
+
+      }
+
+      BitmapFontLineInfo(U32 start)
+      {
+         mStart = start;
+      }
+   };
+}
+
+#endif // _BITMAP_FONT_LINE_INFO_H_

+ 4 - 6
modules/ImageFontToy/1/main.cs

@@ -42,17 +42,15 @@ function ImageFontToy::reset( %this )
     // Create the image font.
     // Create the image font.
     %object = new TextSprite()
     %object = new TextSprite()
     {
     {
-        font = "ToyAssets:OratorBoldFont";
-        fontSize = 6;
+        font = "ToyAssets:ArialFont";
+        fontSize = 5;
         position = "0 0";
         position = "0 0";
-        text = "Hello World!";
-        size = "30 30";
+        text = "The rain in Spain falls mainly on the plain!";
+        size = "25 25";
         BlendColor = "1 1 1 1";
         BlendColor = "1 1 1 1";
         AngularVelocity = 30;
         AngularVelocity = 30;
     };
     };
 
 
-    $f = %object;
-
     // Add the sprite to the scene.
     // Add the sprite to the scene.
     SandboxScene.add( %object );
     SandboxScene.add( %object );
 }
 }