Ver Fonte

TextSprite Complete!

This completes the TextSprite by adding support to change the color,
scale, and size of individual letters.  It also adds the TextSpriteToy
to demonstrate some of the new things that are possible.  Finally, I
removed the ImageFont class.
Peter Robinson há 9 anos atrás
pai
commit
01251c2e0b

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

@@ -270,7 +270,6 @@
     <ClCompile Include="..\..\source\2d\gui\guiSpriteCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\SceneWindow.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\CompositeSprite.cc" />
-    <ClCompile Include="..\..\source\2d\sceneobject\ImageFont.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\ParticlePlayer.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObject.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObjectList.cc" />
@@ -707,8 +706,6 @@
     <ClInclude Include="..\..\source\2d\gui\SceneWindow_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\CompositeSprite.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\CompositeSprite_ScriptBinding.h" />
-    <ClInclude Include="..\..\source\2d\sceneobject\ImageFont.h" />
-    <ClInclude Include="..\..\source\2d\sceneobject\ImageFont_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObject.h" />

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

@@ -1254,9 +1254,6 @@
     <ClCompile Include="..\..\source\2d\core\ParticleSystem.cc">
       <Filter>2d\core</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\2d\sceneobject\ImageFont.cc">
-      <Filter>2d\sceneobject</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\assets\declaredAssets.cc">
       <Filter>assets</Filter>
     </ClCompile>
@@ -2699,12 +2696,6 @@
     <ClInclude Include="..\..\source\2d\core\ParticleSystem.h">
       <Filter>2d\core</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\2d\sceneobject\ImageFont.h">
-      <Filter>2d\sceneobject</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\source\2d\sceneobject\ImageFont_ScriptBinding.h">
-      <Filter>2d\sceneobject</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\assets\declaredAssets.h">
       <Filter>assets</Filter>
     </ClInclude>

+ 0 - 400
engine/source/2d/sceneobject/ImageFont.cc

@@ -1,400 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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 _DGL_H_
-#include "graphics/dgl.h"
-#endif
-
-#include "console/consoleTypes.h"
-
-#include "io/bitStream.h"
-
-#include "string/stringBuffer.h"
-
-#include "ImageFont.h"
-
-// Script bindings.
-#include "ImageFont_ScriptBinding.h"
-
-//------------------------------------------------------------------------------
-
-static EnumTable::Enums textAlignmentEnums[] = 
-{
-    { ImageFont::ALIGN_LEFT,      "Left" },
-    { ImageFont::ALIGN_CENTER,    "Center" },
-    { ImageFont::ALIGN_RIGHT,     "Right" },
-};
-
-static EnumTable gTextAlignmentTable(3, &textAlignmentEnums[0]); 
-
-//-----------------------------------------------------------------------------
-
-ImageFont::TextAlignment ImageFont::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 (TextAlignment)textAlignmentEnums[i].index;
-    }
-
-    // Warn.
-    Con::warnf("ImageFont::getTextAlignmentEnum() - Invalid text alignment of '%s'", label );
-
-    return ImageFont::INVALID_ALIGN;
-}
-
-//-----------------------------------------------------------------------------
-
-const char* ImageFont::getTextAlignmentDescription(const ImageFont::TextAlignment alignment)
-{
-    // 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( "ImageFont::getTextAlignmentDescription() - Invalid text alignment.");
-
-    return StringTable->EmptyString;
-}
-
-//------------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT(ImageFont);
-
-//-----------------------------------------------------------------------------
-
-ImageFont::ImageFont() :
-    mTextAlignment( ImageFont::ALIGN_CENTER ),
-    mFontSize( 1.0f, 1.0f ),
-    mFontPadding( 0 )
-{
-   // Use a static body by default.
-   mBodyDefinition.type = b2_staticBody;
-
-    // Set as auto-sizing.
-    mAutoSizing = true;
-}
-
-//-----------------------------------------------------------------------------
-
-ImageFont::~ImageFont()
-{
-}
-
-//-----------------------------------------------------------------------------
-
-void ImageFont::initPersistFields()
-{    
-    // Call parent.
-    Parent::initPersistFields();
-
-    addProtectedField("image", TypeImageAssetPtr, Offset(mImageAsset, ImageFont), &setImage, &getImage, &writeImage, "");
-    addProtectedField("text", TypeString, 0, setText, getText, &writeText, "The text to be displayed." );  
-    addProtectedField("textAlignment", TypeEnum, Offset(mTextAlignment, ImageFont), &setTextAlignment, &defaultProtectedGetFn, &writeTextAlignment, 1, &gTextAlignmentTable, "");
-    addProtectedField("fontSize", TypeVector2, Offset(mFontSize, ImageFont), &setFontSize, &defaultProtectedGetFn,&writeFontSize, "" );
-    addProtectedField("fontPadding", TypeF32, Offset(mFontPadding, ImageFont), &setFontPadding, &defaultProtectedGetFn, &writeFontPadding, "" );
-}
-
-//-----------------------------------------------------------------------------
-
-bool ImageFont::onAdd()
-{
-    // Call Parent.
-    if(!Parent::onAdd())
-        return false;
-    
-    // Return Okay.
-    return true;
-}
-
-//-----------------------------------------------------------------------------
-
-void ImageFont::onRemove()
-{
-    // Call Parent.
-    Parent::onRemove();
-}
-
-//------------------------------------------------------------------------------
-
-void ImageFont::copyTo(SimObject* object)
-{
-    // Fetch font object.
-    ImageFont* pFontObject = dynamic_cast<ImageFont*>(object);
-
-    // Sanity.
-    AssertFatal(pFontObject != NULL, "ImageFont::copyTo() - Object is not the correct type.");
-
-    // Call parent.
-    Parent::copyTo(object);
-
-    // Copy.
-    pFontObject->setImage( getImage() );
-    pFontObject->setText( getText() );
-    pFontObject->setTextAlignment( getTextAlignment() );
-    pFontObject->setFontSize( getFontSize() );
-    pFontObject->setFontPadding( getFontPadding() );
-}
-
-//------------------------------------------------------------------------------
-
-void ImageFont::scenePrepareRender( const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue )
-{
-    // Create a default render request.
-    Scene::createDefaultRenderRequest( pSceneRenderQueue, this );
-}
-
-//------------------------------------------------------------------------------
-
-void ImageFont::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
-{
-    // Finish if no image asset.
-    if ( mImageAsset.isNull() )
-        return;
-
-    // Fetch number of characters to render.
-    const U32 renderCharacters = mText.length();
-
-    // Ignore if no text to render.
-    if( renderCharacters == 0 )
-        return;
-
-    // Fetch render OOBB.
-    const Vector2& renderOOBB0 = mRenderOOBB[0];
-    const Vector2& renderOOBB1 = mRenderOOBB[1];
-    const Vector2& renderOOBB3 = mRenderOOBB[3];
-
-    Vector2 characterOOBB0;
-    Vector2 characterOOBB1;
-    Vector2 characterOOBB2;
-    Vector2 characterOOBB3;
-
-    // Calculate the starting render position based upon text alignment.
-    switch( mTextAlignment )
-    {
-        case ALIGN_LEFT:
-            {
-                // Size is twice the padded text width as we're aligning to the left from the position expanding rightwards.
-                characterOOBB0.Set( (renderOOBB0.x + renderOOBB1.x)*0.5f, renderOOBB0.y );
-            }
-            break;
-
-        case ALIGN_RIGHT:
-            {
-                // Size is twice the padded text width as we're aligning to the right from the position expanding leftwards.
-                characterOOBB0 = renderOOBB0;
-            }
-            break;
-
-        default:
-            {
-                // Warn.
-                Con::warnf("ImageFont() - Unknown text alignment!");
-            }
-        case ALIGN_CENTER:
-            {
-                // Size is the total padded text size as we're simply centered on the position.
-                characterOOBB0 = renderOOBB0;
-            }
-            break;
-    }
-
-    // Calculate character width stride.
-    Vector2 characterWidthStride = (renderOOBB1 - renderOOBB0);
-    characterWidthStride.Normalize( mFontSize.x + mFontPadding );
-
-    // Calculate character height stride.
-    Vector2 characterHeightStride = (renderOOBB3 - renderOOBB0);
-    characterHeightStride.Normalize( mFontSize.y );
-
-    // Complete character OOBB.
-    characterOOBB1 = characterOOBB0 + characterWidthStride;
-    characterOOBB2 = characterOOBB1 + characterHeightStride;
-    characterOOBB3 = characterOOBB2 - characterWidthStride;
-
-    // Render all the characters.    
-    for( U32 characterIndex = 0; characterIndex < renderCharacters; ++characterIndex )
-    {
-        // Fetch character.
-        U32 character = mText.getChar( characterIndex );
-
-        // Set character to "space" if it's out of bounds.
-        if ( character < 32 || character > 128 )
-            character = 32;
-
-        // Calculate character frame index.
-        const U32 characterFrameIndex = character - 32;
-
-        // Fetch current frame area.
-        const ImageAsset::FrameArea::TexelArea& texelFrameArea = mImageAsset->getImageFrameArea( characterFrameIndex ).mTexelArea;
-
-        // Fetch lower/upper texture coordinates.
-        const Vector2& texLower = texelFrameArea.mTexelLower;
-        const Vector2& texUpper = texelFrameArea.mTexelUpper;
-
-        // Submit batched quad.
-        pBatchRenderer->SubmitQuad(
-            characterOOBB0,
-            characterOOBB1,
-            characterOOBB2,
-            characterOOBB3,
-            Vector2( texLower.x, texUpper.y ),
-            Vector2( texUpper.x, texUpper.y ),
-            Vector2( texUpper.x, texLower.y ),
-            Vector2( texLower.x, texLower.y ),
-            mImageAsset->getImageTexture() );
-
-        // Translate character OOBB.
-        characterOOBB0 += characterWidthStride;
-        characterOOBB1 += characterWidthStride;
-        characterOOBB2 += characterWidthStride;
-        characterOOBB3 += characterWidthStride;
-    }
-}
-
-
-//-----------------------------------------------------------------------------
-
-bool ImageFont::setImage( const char* pImageAssetId )
-{
-    // Set asset.
-    mImageAsset = pImageAssetId;
-
-    // Finish if no image asset.
-    if ( mImageAsset.isNull() )
-        return false;
-
-    // We need a minimum of 96 frames here.
-    if ( mImageAsset->getFrameCount() < 96 )
-    {
-        // Warn.
-        Con::warnf("ImageFont::setImage() - The image needs to have at least 96 frames to be used as a font! (%s)", mImageAsset.getAssetId() );
-        mImageAsset.clear();
-        return false;
-    }
-    
-    // Return Okay.
-    return true;
-}
-
-//-----------------------------------------------------------------------------
-
-void ImageFont::setText( const StringBuffer& text )
-{
-    // Set text.
-    mText.set( &text );
-    calculateSpatials();   
-}
-
-//-----------------------------------------------------------------------------
-
-void ImageFont::setTextAlignment( const TextAlignment alignment )
-{
-    mTextAlignment = alignment;
-    calculateSpatials();
-}
-
-//-----------------------------------------------------------------------------
-
-void ImageFont::setFontSize( const Vector2& size )
-{
-    mFontSize = size;
-    mFontSize.clampZero();
-    calculateSpatials();
-}
-
-//-----------------------------------------------------------------------------
-
-void ImageFont::setFontPadding( const F32 padding )
-{
-    mFontPadding = padding;
-    calculateSpatials();
-}
-
-//-----------------------------------------------------------------------------
-
-void ImageFont::calculateSpatials( void )
-{
-    // Fetch number of characters to render.
-    const U32 renderCharacters = mText.length();
-
-    // Set size as a single character if no text.
-    if ( renderCharacters == 0 )
-    {
-        setSize( mFontSize );
-        return;
-    }
-
-    // Calculate total font padding.
-    const F32 totalFontPadding = (renderCharacters * mFontPadding) - mFontPadding;
-
-    // Calculate total character size.
-    const Vector2 totalFontSize( renderCharacters * mFontSize.x, mFontSize.y );
-
-    // Calculate total padded text size.
-    const Vector2 totalPaddedTextSize( totalFontSize.x + totalFontPadding, totalFontSize.y );
-
-    // Calculate size (AABB) including alignment relative to position.
-    // NOTE:    For left/right alignment we have to double the size width as clipping is based upon size and
-    //          we're aligning to the position here.  We cannot align to the size AABB itself as that changes
-    //          as the text length changes therefore it is not a stable point from which to align from.
-    switch( mTextAlignment )
-    {
-        case ALIGN_LEFT:
-            {
-                // Size is twice the padded text width as we're aligning to the left from the position expanding rightwards.
-                setSize( totalPaddedTextSize.x * 2.0f, totalPaddedTextSize.y );
-            }
-            break;
-
-        case ALIGN_RIGHT:
-            {
-                // Size is twice the padded text width as we're aligning to the right from the position expanding leftwards.
-                setSize( totalPaddedTextSize.x * 2.0f, totalPaddedTextSize.y );
-            }
-            break;
-
-        case ALIGN_CENTER:
-            {
-                // Size is the total padded text size as we're simply centered on the position.
-                setSize( totalPaddedTextSize );
-            }
-            break;
-
-        default:
-            {
-                // Warn.
-                Con::warnf("ImageFont() - Unknown text alignment!");
-            }
-    }
-}
-
-//-----------------------------------------------------------------------------
-
-bool ImageFont::setTextAlignment( void* obj, const char* data )
-{
-    static_cast<ImageFont*>( obj )->setTextAlignment( getTextAlignmentEnum(data) ); return false;
-}

+ 0 - 133
engine/source/2d/sceneobject/ImageFont.h

@@ -1,133 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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_OBJECT_H_
-#define _BITMAP_FONT_OBJECT_H_
-
-#ifndef _STRINGBUFFER_H_
-#include "string/stringBuffer.h"
-#endif
-
-#ifndef _IMAGE_ASSET_H_
-#include "2d/assets/ImageAsset.h"
-#endif
-
-#ifndef _SCENE_OBJECT_H_
-#include "2d/sceneobject/SceneObject.h"
-#endif
-
-#ifndef _ASSET_PTR_H_
-#include "assets/assetPtr.h"
-#endif
-
-#ifndef _UTILITY_H_
-#include "2d/core/utility.h"
-#endif
-
-//-----------------------------------------------------------------------------
-
-class ImageFont : public SceneObject
-{
-    typedef SceneObject          Parent;
-
-public:
-    enum TextAlignment
-    {
-        INVALID_ALIGN,
-
-        ALIGN_LEFT,
-        ALIGN_CENTER,
-        ALIGN_RIGHT
-    };
-
-private:
-    struct TextCell
-    {
-        char CharValue;
-        U32 FrameCell;
-
-        TextCell(char charValue, U32 frameCell)
-        {
-            CharValue = charValue;
-            FrameCell = frameCell;
-        }
-    };
-
-private:
-    AssetPtr<ImageAsset>    mImageAsset;
-    StringBuffer            mText;
-    F32                     mFontPadding;
-    Vector2                 mFontSize;
-    TextAlignment           mTextAlignment;
-
-private:
-    void calculateSpatials( void );
-
-public:
-    ImageFont();
-    ~ImageFont();
-
-    static void initPersistFields();
-
-    bool onAdd();
-    void onRemove();
-    void copyTo(SimObject* object);
-
-    virtual bool canPrepareRender( void ) const                             { return true; }
-    virtual bool validRender( void ) const                                  { return mImageAsset.notNull() && mText.length() > 0; }
-    virtual bool shouldRender( void ) const                                 { return true; }
-    virtual void scenePrepareRender( const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue );
-    virtual void sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer );
-
-    bool setImage( const char* pImageAssetId );
-    const char* getImage( void ) const                                      { return mImageAsset.getAssetId(); };
-    void setText( const StringBuffer& text );
-    inline StringBuffer& getText( void )                                    { return mText; }
-    void setTextAlignment( const TextAlignment alignment );
-    inline TextAlignment getTextAlignment( void ) const                     { return mTextAlignment; }
-    void setFontSize( const Vector2& size );
-    inline Vector2 getFontSize( void ) const                                { return mFontSize; }
-    void setFontPadding( const F32 padding );
-    inline F32 getFontPadding( void ) const                                 { return mFontPadding; }
-
-    static TextAlignment getTextAlignmentEnum(const char* label);
-    static const char* getTextAlignmentDescription(const TextAlignment alignment);
-
-    // Declare Console Object.
-    DECLARE_CONOBJECT(ImageFont);
-
-protected:
-    static bool setImage(void* obj, const char* data)                       { static_cast<ImageFont*>(obj)->setImage( data ); return false; }
-    static const char* getImage(void* obj, const char* data)                { return static_cast<ImageFont*>(obj)->getImage(); }
-    static bool writeImage( void* obj, StringTableEntry pFieldName )        { return static_cast<ImageFont*>(obj)->mImageAsset.notNull(); }
-    static bool setText( void* obj, const char* data )                      { static_cast<ImageFont*>( obj )->setText( data ); return false; }
-    static const char* getText( void* obj, const char* data )               { return static_cast<ImageFont*>( obj )->getText().getPtr8(); }
-    static bool writeText( void* obj, StringTableEntry pFieldName )         { return static_cast<ImageFont*>(obj)->mText.length() != 0; }
-    static bool setTextAlignment( void* obj, const char* data );
-    static bool writeTextAlignment( void* obj, StringTableEntry pFieldName ){return static_cast<ImageFont*>(obj)->getTextAlignment() != ImageFont::ALIGN_CENTER; }
-    static bool setFontSize( void* obj, const char* data )                  { static_cast<ImageFont*>( obj )->setFontSize( Utility::mGetStringElementVector(data) ); return false; }
-	static bool writeFontSize( void* obj, StringTableEntry pFieldName )     { return static_cast<ImageFont*>(obj)->getFontSize().notEqual(Vector2::getOne()); }	
-    static bool setFontPadding( void* obj, const char* data )               { static_cast<ImageFont*>( obj )->setFontPadding( dAtof(data) ); return false; }
-    static bool writeFontPadding( void* obj, StringTableEntry pFieldName )  { return static_cast<ImageFont*>(obj)->getFontPadding() != 0; }
-};
-
-#endif // _BITMAP_FONT_OBJECT_H_

+ 0 - 161
engine/source/2d/sceneobject/ImageFont_ScriptBinding.h

@@ -1,161 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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.
-//-----------------------------------------------------------------------------
-
-ConsoleMethodGroupBeginWithDocs(ImageFont, SceneObject)
-
-/*! Sets the image asset to use..
-    @param imageName The image asset to use.
-    @return Returns true on success.
-*/
-ConsoleMethodWithDocs(ImageFont, setImage, ConsoleBool, 3, 3, (imageAssetId))
-{
-    // Set Image.
-    return object->setImage( argv[2] );
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets current image asset..
-    @return The current image asset.
-*/
-ConsoleMethodWithDocs(ImageFont, getImage, ConsoleString, 2, 2, ())
-{
-    // Get Image.
-    return object->getImage();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Set the text to render.
-*/
-ConsoleMethodWithDocs(ImageFont, setText, ConsoleVoid, 3, 3, (text))
-{
-    object->setText(argv[2]);
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets the text being rendered.
-*/
-ConsoleMethodWithDocs(ImageFont, getText, ConsoleString, 2, 2, ())
-{
-    return object->getText().getPtr8();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Set the text alignment to 'left', 'center' or 'right'.
-    @param alignment The text alignment of 'left', 'center' or 'right'.
-    @return No return value.
-*/
-ConsoleMethodWithDocs(ImageFont, setTextAlignment, ConsoleVoid, 3, 3, (alignment))
-{
-
-    object->setTextAlignment( ImageFont::getTextAlignmentEnum(argv[2]) );
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets the text alignment.
-    @return The text alignment of 'left', 'center' or 'right'.
-*/
-ConsoleMethodWithDocs(ImageFont, getTextAlignment, ConsoleString, 2, 2, ())
-{
-    return ImageFont::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.
-*/
-ConsoleMethodWithDocs(ImageFont, setFontSize, ConsoleVoid, 3, 4, (width, height))
-{
-    F32 width, height;
-
-    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));
-    }
-
-    // (width, [height])
-    else if (elementCount == 1)
-    {
-        width = dAtof(argv[2]);
-
-        if (argc > 3)
-            height = dAtof(argv[3]);
-        else
-            height = width;
-    }
-    // Invalid
-    else
-    {
-        Con::warnf("ImageFont::setFontSize() - Invalid number of parameters!");
-        return;
-    }
-
-    // Set character size.
-    object->setFontSize(Vector2(width, height));
-
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets the size of the font characters.
-    @return The size of the font characters.
-*/
-ConsoleMethodWithDocs(ImageFont, getFontSize, ConsoleString, 2, 2, ())
-{
-    return object->getFontSize().scriptThis();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Set the font padding.
-    @param padding The space added in-between font characters.
-    @return No return value.
-*/
-ConsoleMethodWithDocs(ImageFont, setFontPadding, ConsoleVoid, 3, 3, (padding))
-{
-   // Set character padding.
-   object->setFontPadding( dAtof(argv[2]) );
-
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets the font padding.
-    @return The font padding.
-*/
-ConsoleMethodWithDocs(ImageFont, getFontPadding, ConsoleFloat, 2, 2, ())
-{
-    return object->getFontPadding();
-}
-
-ConsoleMethodGroupEndWithDocs(ImageFont)

+ 202 - 28
engine/source/2d/sceneobject/TextSprite.cc

@@ -293,8 +293,8 @@ void TextSprite::initPersistFields()
     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("textAlignment", TypeEnum, Offset(mTextAlign, TextSprite), &setTextAlignment, &defaultProtectedGetFn, &writeTextAlignment, 1, &gTextAlignmentTable, "");
+    addProtectedField("textVAlignment", 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, "");
@@ -348,6 +348,7 @@ void TextSprite::copyTo(SimObject* object)
     pFontObject->setAutoLineHeight(getAutoLineHeight());
     pFontObject->setCustomLineHeight(getCustomLineHeight());
     pFontObject->setKerning(getKerning());
+    pFontObject->mCharInfo = mCharInfo;
 }
 
 //------------------------------------------------------------------------------
@@ -447,7 +448,7 @@ void TextSprite::sceneRender( const SceneRenderState* pSceneRenderState, const S
 
         if (characterIndex >= mLine[row].mStart)
         {
-           RenderLetter(pBatchRenderer, cursor, charID, ratio);
+           RenderLetter(pBatchRenderer, cursor, charID, ratio, characterIndex);
         }
         
         if ((row + 1) < mLine.size() && mLine[row + 1].mStart == (characterIndex + 1))
@@ -485,10 +486,20 @@ 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, U32 charNum)
 {
    const BitmapFontCharacter& bmChar = mFontAsset->mBitmapFont.getCharacter(charID);
 
+   Vector2 charScale = getCharacterScale(charNum);
+   Vector2 charOffset = getCharacterOffset(charNum);
+   ColorF charColor = getCharacterBlendColor(charNum);
+
+   F32 fontScaleX = mFontScaleX * charScale.x;
+   F32 fontScaleY = mFontScaleY * charScale.y;
+
+   F32 cursorX = cursor.x + charOffset.x - (bmChar.mWidth * ratio * mFontScaleX * ((charScale.x - 1) / 2));
+   F32 cursorY = cursor.y - charOffset.y;
+
    //inset, for hiding part of a letter
    F32 insetLeft, insetRight, insetTop, insetBottom;
    insetLeft = 0;
@@ -499,17 +510,17 @@ void TextSprite::RenderLetter(BatchRender* pBatchRenderer, Vector2& cursor, U32
    // Cropping time!
    if (mOverflowX == OVERFLOW_X_HIDDEN) 
    {
-      if ((cursor.x + (bmChar.mWidth * ratio * mFontScaleX) <= 0) || (cursor.x >= mSize.x))
+      if ((cursorX + (bmChar.mWidth * ratio * fontScaleX) <= 0) || (cursorX >= mSize.x))
          return;
 
-      if (cursor.x < 0 && (cursor.x + (bmChar.mWidth * ratio * mFontScaleX) > 0))
+      if (cursorX < 0 && (cursorX + (bmChar.mWidth * ratio * fontScaleX) > 0))
       {
-         insetLeft = -(cursor.x / (bmChar.mWidth * ratio * mFontScaleX));
+         insetLeft = -(cursorX / (bmChar.mWidth * ratio * fontScaleX));
       }
 
-      if (cursor.x < mSize.x && (cursor.x + (bmChar.mWidth * ratio * mFontScaleX) > mSize.x))
+      if (cursorX < mSize.x && (cursorX + (bmChar.mWidth * ratio * fontScaleX) > mSize.x))
       {
-         insetRight = (((cursor.x + (bmChar.mWidth * ratio * mFontScaleX)) - mSize.x) / (bmChar.mWidth * ratio * mFontScaleX));
+         insetRight = (((cursorX + (bmChar.mWidth * ratio * fontScaleX)) - mSize.x) / (bmChar.mWidth * ratio * fontScaleX));
       }
 
       if (insetLeft + insetRight > 1)
@@ -518,20 +529,20 @@ void TextSprite::RenderLetter(BatchRender* pBatchRenderer, Vector2& cursor, U32
    if (mOverflowY == OVERFLOW_Y_HIDDEN)
    {
       F32 tempTop, tempBottom;
-      tempTop = cursor.y - (mFontAsset->mBitmapFont.mBaseline * ratio * mFontScaleY);
-      tempBottom = tempTop + (bmChar.mHeight * ratio * mFontScaleY);
+      tempTop = cursorY - (mFontAsset->mBitmapFont.mBaseline * ratio * fontScaleY) + (bmChar.mYOffset * ratio * fontScaleY);
+      tempBottom = tempTop + (bmChar.mHeight * ratio * fontScaleY);
 
       if ((tempBottom <= 0) || (tempTop >= mSize.y))
          return;
 
       if (tempTop < 0 && tempBottom > 0)
       {
-         insetTop = -(tempTop / (bmChar.mHeight * ratio * mFontScaleY));
+         insetTop = -(tempTop / (bmChar.mHeight * ratio * fontScaleY));
       }
 
       if (tempTop < mSize.y && tempBottom > mSize.y)
       {
-         insetBottom = (tempBottom - mSize.y) / (bmChar.mHeight * ratio * mFontScaleY);
+         insetBottom = (tempBottom - mSize.y) / (bmChar.mHeight * ratio * fontScaleY);
       }
 
       if (insetTop + insetBottom > 1)
@@ -547,16 +558,16 @@ void TextSprite::RenderLetter(BatchRender* pBatchRenderer, Vector2& cursor, U32
 
    //create the destination rect
    Vector2 destLeft = (mRenderOOBB[1] - mRenderOOBB[0]);
-   destLeft.Normalize((F32)cursor.x + (insetLeft * bmChar.mWidth * ratio * mFontScaleX));
+   destLeft.Normalize((F32)cursorX + (insetLeft * bmChar.mWidth * ratio * fontScaleX));
 
    Vector2 destWidth = (mRenderOOBB[1] - mRenderOOBB[0]);
-   destWidth.Normalize(((bmChar.mWidth * ratio) - (insetLeft * (bmChar.mWidth * ratio)) - (insetRight * (bmChar.mWidth * ratio))) * mFontScaleX);
+   destWidth.Normalize(((bmChar.mWidth * ratio) - (insetLeft * (bmChar.mWidth * ratio)) - (insetRight * (bmChar.mWidth * ratio))) * fontScaleX);
 
    Vector2 destTop = -(mRenderOOBB[3] - mRenderOOBB[0]);
-   destTop.Normalize((F32)cursor.y - (((mFontAsset->mBitmapFont.mBaseline * ratio) - (bmChar.mYOffset * ratio) - (insetTop * bmChar.mHeight * ratio)) * mFontScaleY));
+   destTop.Normalize((F32)cursorY - (((mFontAsset->mBitmapFont.mBaseline * ratio) - (bmChar.mYOffset * ratio) - (insetTop * bmChar.mHeight * ratio)) * fontScaleY));
 
    Vector2 destHeight = -(mRenderOOBB[3] - mRenderOOBB[0]);
-   destHeight.Normalize(((bmChar.mHeight * ratio) - (insetBottom * bmChar.mHeight * ratio) - (insetTop * bmChar.mHeight * ratio)) * mFontScaleY);
+   destHeight.Normalize(((bmChar.mHeight * ratio) - (insetBottom * bmChar.mHeight * ratio) - (insetTop * bmChar.mHeight * ratio)) * fontScaleY);
 
    Vector2 destOOBB[4];
    destOOBB[0] = (mRenderOOBB[3] + destLeft + destTop + destHeight);
@@ -564,17 +575,35 @@ void TextSprite::RenderLetter(BatchRender* pBatchRenderer, Vector2& cursor, U32
    destOOBB[2] = (mRenderOOBB[3] + destLeft + destWidth + destTop);
    destOOBB[3] = (mRenderOOBB[3] + destLeft + destTop);
 
-   // Submit batched quad.
-   pBatchRenderer->SubmitQuad(
-      destOOBB[0],
-      destOOBB[1],
-      destOOBB[2],
-      destOOBB[3],
-      sourceOOBB[0],
-      sourceOOBB[1],
-      sourceOOBB[2],
-      sourceOOBB[3],
-      mFontAsset->getImageTexture(bmChar.mPage));
+   if (charColor != mBlendColor)
+   {
+      // Submit batched quad.
+      pBatchRenderer->SubmitQuad(
+         destOOBB[0],
+         destOOBB[1],
+         destOOBB[2],
+         destOOBB[3],
+         sourceOOBB[0],
+         sourceOOBB[1],
+         sourceOOBB[2],
+         sourceOOBB[3],
+         mFontAsset->getImageTexture(bmChar.mPage),
+         charColor);
+   }
+   else
+   {
+      // Submit batched quad.
+      pBatchRenderer->SubmitQuad(
+         destOOBB[0],
+         destOOBB[1],
+         destOOBB[2],
+         destOOBB[3],
+         sourceOOBB[0],
+         sourceOOBB[1],
+         sourceOOBB[2],
+         sourceOOBB[3],
+         mFontAsset->getImageTexture(bmChar.mPage));
+   }
 }
 
 //-----------------------------------------------------------------------------
@@ -739,3 +768,148 @@ bool TextSprite::setFont( const char* pFontAssetId )
     // Return Okay.
     return true;
 }
+
+//-----------------------------------------------------------------------------
+
+void TextSprite::setCharacterBlendColor(const U32 charNum, const ColorF color)
+{
+   if (mCharInfo.find(charNum) != mCharInfo.end())
+   {
+      mCharInfo[charNum].mColor = color;
+      mCharInfo[charNum].mUseColor = true;
+   }
+   else
+   {
+      mCharInfo.emplace(charNum, BitmapFontCharacterInfo(color));
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+ColorF TextSprite::getCharacterBlendColor(const U32 charNum)
+{
+   if (mCharInfo.find(charNum) != mCharInfo.end())
+   {
+      return mCharInfo[charNum].mColor;
+   }
+   else
+   {
+      return mBlendColor;
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+bool TextSprite::getCharacterHasBlendColor(const U32 charNum)
+{
+   return (mCharInfo.find(charNum) != mCharInfo.end() && mCharInfo[charNum].mUseColor);
+}
+
+//-----------------------------------------------------------------------------
+
+void TextSprite::resetCharacterBlendColor(const U32 charNum)
+{
+   if (mCharInfo.find(charNum) != mCharInfo.end())
+   {
+      mCharInfo[charNum].mUseColor = false;
+
+      if (mCharInfo[charNum].isDefault())
+      {
+         mCharInfo.erase(charNum);
+      }
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+void TextSprite::setCharacterScale(const U32 charNum, const F32 scaleX, const F32 scaleY)
+{
+   if (mCharInfo.find(charNum) == mCharInfo.end())
+   {
+      mCharInfo.emplace(charNum, BitmapFontCharacterInfo());
+   }
+   mCharInfo[charNum].mScaleX = scaleX;
+   mCharInfo[charNum].mScaleY = scaleY;
+
+   if (mCharInfo[charNum].isDefault())
+   {
+      mCharInfo.erase(charNum);
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+Vector2 TextSprite::getCharacterScale(const U32 charNum)
+{
+   if (mCharInfo.find(charNum) != mCharInfo.end())
+   {
+      return Vector2(mCharInfo[charNum].mScaleX, mCharInfo[charNum].mScaleY);
+   }
+   else
+   {
+      return Vector2(1.0f, 1.0f);
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+void TextSprite::resetCharacterScale(const U32 charNum)
+{
+   if (mCharInfo.find(charNum) != mCharInfo.end())
+   {
+      mCharInfo[charNum].mScaleX = 1.0f;
+      mCharInfo[charNum].mScaleY = 1.0f;
+
+      if (mCharInfo[charNum].isDefault())
+      {
+         mCharInfo.erase(charNum);
+      }
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+void TextSprite::setCharacterOffset(const U32 charNum, const F32 offsetX, const F32 offsetY)
+{
+   if (mCharInfo.find(charNum) == mCharInfo.end())
+   {
+      mCharInfo.emplace(charNum, BitmapFontCharacterInfo());
+   }
+   mCharInfo[charNum].mOffsetX = offsetX;
+   mCharInfo[charNum].mOffsetY = offsetY;
+
+   if (mCharInfo[charNum].isDefault())
+   {
+      mCharInfo.erase(charNum);
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+Vector2 TextSprite::getCharacterOffset(const U32 charNum)
+{
+   if (mCharInfo.find(charNum) != mCharInfo.end())
+   {
+      return Vector2(mCharInfo[charNum].mOffsetX, mCharInfo[charNum].mOffsetY);
+   }
+   else
+   {
+      return Vector2(0.0f, 0.0f);
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+void TextSprite::resetCharacterOffset(const U32 charNum)
+{
+   if (mCharInfo.find(charNum) != mCharInfo.end())
+   {
+      mCharInfo[charNum].mOffsetX = 0.0f;
+      mCharInfo[charNum].mOffsetY = 0.0f;
+
+      if (mCharInfo[charNum].isDefault())
+      {
+         mCharInfo.erase(charNum);
+      }
+   }
+}

+ 24 - 2
engine/source/2d/sceneobject/TextSprite.h

@@ -47,6 +47,12 @@
 #include "bitmapFont/BitmapFontLineInfo.h"
 #endif
 
+#ifndef _BITMAP_FONT_CHARACTER_INFO_H_
+#include "bitmapFont/BitmapFontCharacterInfo.h"
+#endif
+
+using CharInfoMap = std::map<U32, BitmapFontCharacterInfo>;
+
 //-----------------------------------------------------------------------------
 
 class TextSprite : public SceneObject
@@ -109,6 +115,7 @@ private:
     std::vector<BitmapFontLineInfo> mLine;
     bool                    mFontSpatialsDirty;
     Vector2                 mCalculatedSize;
+    CharInfoMap             mCharInfo;
 
 
 public:
@@ -129,7 +136,7 @@ public:
 
     bool setFont( const char* pFontAssetId );
     const char* getFont(void) const                                         { return mFontAsset.getAssetId(); }
-    inline void setText(const StringBuffer& text)                           { mText.set(&text); mFontSpatialsDirty = true; }
+    inline void setText(const StringBuffer& text)                           { mText.set(&text); mFontSpatialsDirty = true; mCharInfo.clear(); }
     inline StringBuffer& getText(void)                                      { return mText; }
     inline void setFontSize(const F32 size)                                 { mFontSize = size; mFontSpatialsDirty = true; }
     inline F32 getFontSize(void) const                                      { return mFontSize; }
@@ -166,6 +173,21 @@ public:
     inline void setKerning(const F32 kern)                                  { mKerning = kern; mFontSpatialsDirty = true; }
     inline F32 getKerning(void) const                                       { return mKerning; }
 
+    void resetCharacterSettings(void)                                       { mCharInfo.clear(); }
+
+    void setCharacterBlendColor(const U32 charNum, const ColorF color);
+    ColorF getCharacterBlendColor(const U32 charNum);
+    bool getCharacterHasBlendColor(const U32 charNum);
+    void resetCharacterBlendColor(const U32 charNum);
+
+    void setCharacterScale(const U32 charNum, const F32 scaleX, const F32 scaleY);
+    Vector2 getCharacterScale(const U32 charNum);
+    void resetCharacterScale(const U32 charNum);
+
+    void setCharacterOffset(const U32 charNum, const F32 offsetX, const F32 offsetY);
+    Vector2 getCharacterOffset(const U32 charNum);
+    void resetCharacterOffset(const U32 charNum);
+
     // Declare Console Object.
     DECLARE_CONOBJECT(TextSprite);
 
@@ -208,7 +230,7 @@ protected:
     static bool writeKerning(void* obj, StringTableEntry pFieldName)       { return static_cast<TextSprite*>(obj)->getKerning() != 0.0f; }
 
 private:
-   void RenderLetter(BatchRender* pBatchRenderer, Vector2& cursor, U32 charID, F32 ratio);
+   void RenderLetter(BatchRender* pBatchRenderer, Vector2& cursor, U32 charID, F32 ratio, U32 charNum);
    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);

+ 164 - 0
engine/source/2d/sceneobject/TextSprite_ScriptBinding.h

@@ -270,4 +270,168 @@ ConsoleMethodWithDocs(TextSprite, getKerning, ConsoleFloat, 2, 2, ())
    return object->getKerning();
 }
 
+//-----------------------------------------------------------------------------
+
+/*! Resets the blend color, scale, and offset for all characters'.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, resetCharacterSettings, ConsoleVoid, 2, 2, ())
+{
+   object->resetCharacterSettings();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the blend color for an individual character.
+@param index The zero based index for the character.
+@param color The blend color to use for character.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setCharacterBlendColor, ConsoleVoid, 4, 4, (index, color))
+{
+   if (argc < 3)
+   {
+      Con::warnf("TextSprite::setCharacterBlendColor() - Invalid number of parameters!");
+      return;
+   }
+
+   const U32 colorCount = Utility::mGetStringElementCount(argv[3]);
+   if (colorCount != 4)
+   {
+      Con::warnf("TextSprite::setCharacterBlendColor() - Invalid color! Colors require four values (red / green / blue / alpha)!");
+      return;
+   }
+   object->setCharacterBlendColor(dAtoi(argv[2]), ColorF(dAtof(Utility::mGetStringElement(argv[3], 0)),
+                                                         dAtof(Utility::mGetStringElement(argv[3], 1)),
+                                                         dAtof(Utility::mGetStringElement(argv[3], 2)),
+                                                         dAtof(Utility::mGetStringElement(argv[3], 3))));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the blend color for an individual character if set or the blend color for the sprite.
+@param index The zero based index for the character.
+@return The blend color for the character or the sprite.
+*/
+ConsoleMethodWithDocs(TextSprite, getCharacterBlendColor, ConsoleString, 3, 3, (index))
+{
+   U32 charNum = dAtoi(argv[2]);
+   if (object->getCharacterHasBlendColor(charNum))
+   {
+      return object->getCharacterBlendColor(charNum).scriptThis();
+   }
+   else
+   {
+      return object->getBlendColor().scriptThis();
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets if the character is using a custom blend color.
+@param index The zero based index for the character.
+@return True if the character is using a custom blend color or false if the character uses the sprite's blend color.
+*/
+ConsoleMethodWithDocs(TextSprite, getCharacterHasBlendColor, ConsoleBool, 3, 3, (index))
+{
+   return object->getCharacterHasBlendColor(dAtoi(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Resets the blend color for a character so that it uses the sprite's blend color.
+@param index The zero based index for the character.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, resetCharacterBlendColor, ConsoleVoid, 3, 3, (index))
+{
+   object->resetCharacterBlendColor(dAtoi(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the scale of a given character. This is multiplied by the scale of the font to get the total scale.
+@param index The zero based index for the character.
+@param (scaleX / scaleY) The amount to multiply the size of the character by. Default value is 1.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setCharacterScale, ConsoleVoid, 4, 4, (index, scale scaleX / scaleY))
+{
+   U32 charNum = dAtoi(argv[2]);
+
+   const U32 count = Utility::mGetStringElementCount(argv[3]);
+   if (count != 2)
+   {
+      Con::warnf("TextSprite::setCharacterScale() - Invalid number of values (scaleX / scaleY)!");
+      return;
+   }
+
+   object->setCharacterScale(charNum, dAtof(Utility::mGetStringElement(argv[3], 0)), dAtof(Utility::mGetStringElement(argv[3], 1)));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets scale of a given character.
+@param index The zero based index for the character.
+@return (scaleX / scaleY) The scale of the character.
+*/
+ConsoleMethodWithDocs(TextSprite, getCharacterScale, ConsoleString, 3, 3, (index))
+{
+   return object->getCharacterScale(dAtoi(argv[2])).scriptThis();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Resets the scale of a given character.
+@param index The zero based index for the character.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, resetCharacterScale, ConsoleVoid, 3, 3, (index))
+{
+   object->resetCharacterScale(dAtoi(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the offset of a given character.
+@param index The zero based index for the character.
+@param (offsetX / offsetY) The amount to move a character from it's calculated position.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, setCharacterOffset, ConsoleVoid, 4, 4, (index, offset offsetX / offsetY))
+{
+   U32 charNum = dAtoi(argv[2]);
+
+   const U32 count = Utility::mGetStringElementCount(argv[3]);
+   if (count != 2)
+   {
+      Con::warnf("TextSprite::setCharacterOffset() - Invalid number of values (offsetX / offsetY)!");
+      return;
+   }
+
+   object->setCharacterOffset(charNum, dAtof(Utility::mGetStringElement(argv[3], 0)), dAtof(Utility::mGetStringElement(argv[3], 1)));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets offset of a given character.
+@param index The zero based index for the character.
+@return (offsetX / offsetY) The offset of the character.
+*/
+ConsoleMethodWithDocs(TextSprite, getCharacterOffset, ConsoleString, 3, 3, (index))
+{
+   return object->getCharacterOffset(dAtoi(argv[2])).scriptThis();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Resets the offset of a given character.
+@param index The zero based index for the character.
+@return No return value.
+*/
+ConsoleMethodWithDocs(TextSprite, resetCharacterOffset, ConsoleVoid, 3, 3, (index))
+{
+   object->resetCharacterOffset(dAtoi(argv[2]));
+}
+
 ConsoleMethodGroupEndWithDocs(TextSprite)

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

@@ -0,0 +1,61 @@
+//-----------------------------------------------------------------------------
+// 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_CHARACTER_INFO_H_
+#define _BITMAP_FONT_CHARACTER_INFO_H_
+
+#ifndef _UTILITY_H_
+#include "2d/core/utility.h"
+#endif
+
+#ifndef _COLOR_H_
+#include "graphics/color.h"
+#endif
+
+namespace font
+{
+   struct BitmapFontCharacterInfo
+   {
+   public:
+      bool mUseColor;
+      ColorF mColor;
+      F32 mOffsetX;
+      F32 mOffsetY;
+      F32 mScaleX;
+      F32 mScaleY;
+
+      BitmapFontCharacterInfo() : mUseColor(false), mColor(1.0f, 1.0f, 1.0f, 1.0f), mOffsetX(0.0f), mOffsetY(0.0f), mScaleX(1.0f), mScaleY(1.0f)
+      {
+
+      }
+
+      BitmapFontCharacterInfo(ColorF color) : mOffsetX(0.0f), mOffsetY(0.0f), mScaleX(1.0f), mScaleY(1.0f)
+      {
+         mColor = color;
+         mUseColor = true;
+      }
+
+      inline bool isDefault() { return (!mUseColor && mOffsetX == 0.0f && mOffsetY == 0.0f && mScaleX == 1.0f && mScaleY == 1.0f); }
+   };
+}
+
+#endif // _BITMAP_FONT_CHARACTER_INFO_H_

+ 0 - 56
modules/ImageFontToy/1/main.cs

@@ -1,56 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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.
-//-----------------------------------------------------------------------------
-
-function ImageFontToy::create( %this )
-{
-    // Reset the toy.
-    ImageFontToy.reset();
-}
-
-//-----------------------------------------------------------------------------
-
-function ImageFontToy::destroy( %this )
-{
-}
-
-//-----------------------------------------------------------------------------
-
-function ImageFontToy::reset( %this )
-{
-    // Clear the scene.
-    SandboxScene.clear();
-
-    // Create the image font.
-    %object = new TextSprite()
-    {
-        font = "ToyAssets:ArialFont";
-        fontSize = 5;
-        position = "0 0";
-        text = "The rain in Spain falls mainly on the plain!";
-        size = "25 25";
-        BlendColor = "1 1 1 1";
-        AngularVelocity = 30;
-    };
-
-    // Add the sprite to the scene.
-    SandboxScene.add( %object );
-}

+ 251 - 0
modules/TextSpriteToy/1/main.cs

@@ -0,0 +1,251 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+function TextSpriteToy::create( %this )
+{
+    // Reset the toy.
+    TextSpriteToy.reset();
+}
+
+//-----------------------------------------------------------------------------
+
+function TextSpriteToy::destroy( %this )
+{
+}
+
+//-----------------------------------------------------------------------------
+
+function TextSpriteToy::reset( %this )
+{
+    // Clear the scene.
+    SandboxScene.clear();
+
+    //Title
+    new TextSprite()
+    {
+        Scene = SandboxScene;
+        Font = "ToyAssets:TrajanProFont";
+        FontSize = 6.5;
+        Text = "Presenting the TextSprite!";
+        Position = "0 30";
+        Size = "90 7";
+        OverflowModeX = "visible";
+        TextAlignment = "center";
+        BlendColor = "0.2 0.5 1 1";
+    };
+
+    //Opening Description
+    new TextSprite()
+    {
+        Scene = SandboxScene;
+        Font = "ToyAssets:ArialFont";
+        FontSize = 3;
+        Text = "The TextSprite takes a FontAsset which directly loads a bitmap font file, so adding a new font is super easy! The TextSprite let's you align the text to the left, right, center or even justified. It can also be vertically aligned to the top, middle, or bottom. There's multiple overflow options including automatically shrinking text fit the box. Finally, you can control the color, offset, and scale of each character individually! Check out these examples!";
+        Position = "0 19";
+        Size = "90 15";
+        OverflowModeY = "visible";
+        BlendColor = "1 1 1 0.8";
+    };
+
+    %example1 = new TextSprite()
+    {
+        Scene = SandboxScene;
+        Font = "ToyAssets:OratorBoldFont";
+        FontSize = 5;
+        Text = "You can make any letter big or small!";
+        Position = "-30 -8";
+        Size = "24 24";
+        BlendColor = "1 1 1 1";
+    };
+
+    for(%i = 24; %i <= 26; %i++)
+    {
+        %example1.setCharacterScale(%i, "1.7 2");
+    }
+
+    for(%i = 31; %i <= 35; %i++)
+    {
+        %example1.setCharacterScale(%i, "0.8 0.6");
+    }
+
+    %example2 = new TextSprite()
+    {
+        Scene = SandboxScene;
+        Font = "ToyAssets:TrajanProFont";
+        FontSize = 4.3;
+        Text = "Don't be boring! Add some COLOR and let it spin!";
+        Position = "0 -5";
+        Size = "24 24";
+        BlendColor = "1 1 1 1";
+        AngularVelocity = 30;
+        TextAlignment = "center";
+        TextVAlignment = "middle";
+        autoLineHeight = false;
+        customLineHeight = 3.8;
+    };
+    %example2.setCharacterBlendColor(26, "1 0 0 1");
+    %example2.setCharacterBlendColor(27, "1 0.5 0 1");
+    %example2.setCharacterBlendColor(28, "1 1 0 1");
+    %example2.setCharacterBlendColor(29, "0.2 1 0.2 1");
+    %example2.setCharacterBlendColor(30, "0 0.2 1 1");
+
+    %example3 = new TextSprite()
+    {
+        Scene = SandboxScene;
+        Font = "ToyAssets:ArialFont";
+        FontSize = 3.5;
+        Text = "With a little work you can get your text to jump out at your readers!";
+        Position = "30 -8";
+        Size = "24 24";
+        BlendColor = "1 1 1 1";
+        TextAlignment = "right";
+        TextVAlignment = "bottom";
+        Class = "JumpingText";
+        start = 44;
+        end = 47;
+        jumpSpeed = 0;
+        letterHeight = 0;
+        UpdateCallback = true;
+        autoLineHeight = false;
+        customLineHeight = 6;
+    };
+
+    %example4 = new TextSprite()
+    {
+        Scene = SandboxScene;
+        Font = "ToyAssets:ArialFont";
+        FontSize = 3.7;
+        Text = "You could build a dialog box that shows one letter at a time!";
+        Position = "-24 -27";
+        Size = "45 10";
+        OverflowModeY = "visible";
+        BlendColor = "1 1 1 0";
+        Class = "DialogText";
+        pen = 0;
+    };
+    %example4.showLetter();
+
+    %example5 = new TextSprite()
+    {
+        Scene = SandboxScene;
+        Font = "ToyAssets:OratorBoldFont";
+        FontSize = 3.4;
+        Text = "AJDIORQNAKMAKENZCBADTWOLFJEI PEPWQFDNWORDFHISUDFBHAKLSBLH RUEBNAJDUIOQPSEARCHUIRDFBUYJ MBPIRATEIDBGVMCODEWHTKEIAVIE";
+        Position = "24 -25.5";
+        Size = "45 10";
+        OverflowModeY = "visible";
+        BlendColor = "1 1 1 1";
+        Class = "WordSearchText";
+    };
+    %example5.setCharacterBlendColor(4, "1 1 1 1");
+    %example5.setCharacterBlendColor(5, "1 1 1 1");
+    for(%i = 10; %i <= 13; %i++)
+    {
+        %example5.setCharacterBlendColor(%i, "1 1 1 1");
+    }
+    %example5.setCharacterBlendColor(18, "1 1 1 1");
+    for(%i = 37; %i <= 40; %i++)
+    {
+        %example5.setCharacterBlendColor(%i, "1 1 1 1");
+    }
+    for(%i = 71; %i <= 76; %i++)
+    {
+        %example5.setCharacterBlendColor(%i, "1 1 1 1");
+    }
+    %example5.schedule(6000, "fadeOut");
+}
+
+//-----------------------------------------------------------------------------
+
+function JumpingText::onUpdate(%this)
+{
+    if(%this.jumpSpeed == 0 && %this.letterHeight == 0)
+    {
+        //jump again!
+        %this.jumpSpeed = 0.7;
+    }
+
+    %this.letterHeight += %this.jumpSpeed;
+    if(%this.jumpSpeed > 0)
+    {
+        %this.jumpSpeed *= 0.8;
+        if(%this.jumpSpeed < 0.1)
+        {
+            %this.jumpSpeed = -0.1;
+        }
+    }
+    else if(%this.jumpSpeed < 0)
+    {
+        %this.jumpSpeed *= 1.2;
+        if(%this.letterHeight < 0)
+        {
+            %this.letterHeight = 0;
+            %this.jumpSpeed = 0;
+            %this.setUpdateCallback(false);
+            %this.schedule(1000, "setUpdateCallback", true);
+        }
+    }
+
+    for(%i = %this.start; %i <= %this.end; %i++)
+    {
+        %this.setCharacterOffset(%i, "0" SPC %this.letterHeight);
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+function DialogText::showLetter(%this)
+{
+    if(%this.pen == 0)
+    {
+        %this.resetCharacterSettings();
+    }
+    %this.setCharacterBlendColor(%this.pen, "1 1 1 1");
+    %this.pen++;
+    if(%this.pen >= strlen(%this.getText()))
+    {
+        %this.pen = 0;
+        %this.schedule(3000, "showLetter");
+    }
+    else
+    {
+        %this.schedule(80, "showLetter");
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+function WordSearchText::fadeOut(%this)
+{
+    %this.fadeTo("1 1 1 0", 0.6);
+
+    %this.schedule(6000, "fadeIn");
+}
+
+//-----------------------------------------------------------------------------
+
+function WordSearchText::fadeIn(%this)
+{
+    %this.fadeTo("1 1 1 1", 0.6);
+
+    %this.schedule(6000, "fadeOut");
+}

+ 2 - 2
modules/ImageFontToy/1/module.taml → modules/TextSpriteToy/1/module.taml

@@ -1,7 +1,7 @@
 <ModuleDefinition
-	ModuleId="ImageFontToy"
+	ModuleId="TextSpriteToy"
 	VersionId="1"
-	Description="Demonstrates creating an sprite that renders text."
+	Description="Demonstrates the amazing TextSprite!"
 	Dependencies="ToyAssets=1"
 	Type="toy"
 	ToyCategoryIndex="3"