Merge pull request #4025 from Dhilan007/di2893

issues #2893:perfect new label
This commit is contained in:
minggo 2013-10-31 18:46:30 -07:00
commit f684dc0ff7
14 changed files with 556 additions and 378 deletions

View File

@ -60,6 +60,7 @@ THE SOFTWARE.
#include "CCEGLView.h"
#include "CCConfiguration.h"
#include "CCEventDispatcher.h"
#include "CCFontFreeType.h"
/**
Position of the FPS
@ -686,6 +687,8 @@ void Director::purgeDirector()
// purge bitmap cache
LabelBMFont::purgeCachedData();
FontFreeType::shutdownFreeType();
// purge all managed caches
DrawPrimitives::free();
AnimationCache::destroyInstance();

View File

@ -73,13 +73,15 @@ void Font::setCurrentGlyphCollection(GlyphCollection glyphs, const char *customG
break;
default:
int lenght = strlen(customGlyphs);
_customGlyphs = new char [lenght + 2];
memcpy(_customGlyphs, customGlyphs, lenght);
_customGlyphs[lenght] = 0;
_customGlyphs[lenght+1] = 0;
if (customGlyphs)
{
int lenght = strlen(customGlyphs);
_customGlyphs = new char [lenght + 2];
memcpy(_customGlyphs, customGlyphs, lenght);
_customGlyphs[lenght] = 0;
_customGlyphs[lenght+1] = 0;
}
break;
}

View File

@ -9,18 +9,41 @@
#include "cocos2d.h"
#include "CCFontAtlas.h"
#include "CCFont.h"
#include "CCFontFreeType.h"
NS_CC_BEGIN
FontAtlas::FontAtlas(Font &theFont) : _font(theFont)
FontAtlas::FontAtlas(Font &theFont) :
_font(&theFont),
_currentPageData(nullptr)
{
_font.retain();
_font->retain();
FontFreeType* fontTTf = dynamic_cast<FontFreeType*>(_font);
if (fontTTf && fontTTf->isDynamicGlyphCollection())
{
_currentPageLineHeight = _font->getFontMaxHeight();
_commonLineHeight = _currentPageLineHeight * 0.8f;
Texture2D * tex = new Texture2D;
_currentPage = 0;
_currentPageOrigX = 0;
_currentPageOrigY = 0;
_letterPadding = 5;
_currentPageDataSize = (1024 * 1024 * 4);
_currentPageData = new unsigned char[_currentPageDataSize];
memset(_currentPageData, 0, _currentPageDataSize);
addTexture(*tex,0);
tex->release();
}
}
FontAtlas::~FontAtlas()
{
_font.release();
_font->release();
relaseTextures();
delete []_currentPageData;
}
void FontAtlas::relaseTextures()
@ -51,6 +74,146 @@ bool FontAtlas::getLetterDefinitionForChar(unsigned short letteCharUTF16, FontL
}
}
bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String)
{
if(_currentPageData == nullptr)
return false;
FontFreeType* fontTTf = (FontFreeType*)_font;
std::vector<FontLetterDefinition> fontDefs;
int length = cc_wcslen(utf16String);
//find out new letter
for (int i = 0; i < length; ++i)
{
auto outIterator = _fontLetterDefinitions.find(utf16String[i]);
if (outIterator == _fontLetterDefinitions.end())
{
Rect tempRect;
FontLetterDefinition tempDef;
tempDef.offsetX = 0;
tempDef.anchorX = 0.0f;
tempDef.anchorY = 1.0f;
if (!fontTTf->getBBOXFotChar(utf16String[i], tempRect))
{
tempDef.validDefinition = false;
tempDef.letteCharUTF16 = utf16String[i];
tempDef.commonLineHeight = 0;
tempDef.width = 0;
tempDef.height = 0;
tempDef.U = 0;
tempDef.V = 0;
tempDef.offsetY = 0;
tempDef.textureID = 0;
}
else
{
tempDef.validDefinition = true;
tempDef.letteCharUTF16 = utf16String[i];
tempDef.width = tempRect.size.width + _letterPadding;
tempDef.height = _currentPageLineHeight - 1;
tempDef.offsetY = tempRect.origin.y;
tempDef.commonLineHeight = _currentPageLineHeight;
}
fontDefs.push_back(tempDef);
}
}
float scaleFactor = CC_CONTENT_SCALE_FACTOR();
int newLetterCount = fontDefs.size();
float glyphWidth;
for (int i = 0; i < newLetterCount; ++i)
{
if (fontDefs[i].validDefinition)
{
_currentPageOrigX += _letterPadding;
glyphWidth = fontDefs[i].width - _letterPadding;
if (_currentPageOrigX + glyphWidth > 1024)
{
_currentPageOrigY += _currentPageLineHeight;
if(_currentPageOrigY >= 1024)
{
_atlasTextures[_currentPage]->initWithData(_currentPageData, _currentPageDataSize, Texture2D::PixelFormat::RGBA8888, 1024, 1024, Size(1024, 1024) );
_currentPageOrigX = 0;
_currentPageOrigY = 0;
delete []_currentPageData;
_currentPageData = new unsigned char[_currentPageDataSize];
if(_currentPageData == nullptr)
return false;
memset(_currentPageData, 0, _currentPageDataSize);
_currentPage++;
Texture2D* tex = new Texture2D;
addTexture(*tex,_currentPage);
tex->release();
}
}
renderCharAt(fontDefs[i].letteCharUTF16,_currentPageOrigX,_currentPageOrigY,_currentPageData,1024);
fontDefs[i].U = _currentPageOrigX - 1;
fontDefs[i].V = _currentPageOrigY;
fontDefs[i].textureID = _currentPage;
// take from pixels to points
fontDefs[i].width = fontDefs[i].width / scaleFactor;
fontDefs[i].height = fontDefs[i].height / scaleFactor;
fontDefs[i].U = fontDefs[i].U / scaleFactor;
fontDefs[i].V = fontDefs[i].V / scaleFactor;
}
else
glyphWidth = 0;
this->addLetterDefinition(fontDefs[i]);
_currentPageOrigX += glyphWidth;
}
if(newLetterCount > 0)
_atlasTextures[_currentPage]->initWithData(_currentPageData, _currentPageDataSize, Texture2D::PixelFormat::RGBA8888, 1024, 1024, Size(1024, 1024) );
return true;
}
bool FontAtlas::renderCharAt(unsigned short int charToRender, int posX, int posY, unsigned char *destMemory, int destSize)
{
unsigned char *sourceBitmap = 0;
int sourceWidth = 0;
int sourceHeight = 0;
// get the glyph's bitmap
sourceBitmap = _font->getGlyphBitmap(charToRender, sourceWidth, sourceHeight);
if (!sourceBitmap)
return false;
int iX = posX;
int iY = posY;
for (int y = 0; y < sourceHeight; ++y)
{
int bitmap_y = y * sourceWidth;
for (int x = 0; x < sourceWidth; ++x)
{
unsigned char cTemp = sourceBitmap[bitmap_y + x];
// the final pixel
int iTemp = cTemp << 24 | cTemp << 16 | cTemp << 8 | cTemp;
*(int*) &destMemory[(iX + ( iY * destSize ) ) * 4] = iTemp;
iX += 1;
}
iX = posX;
iY += 1;
}
//everything good
return true;
}
void FontAtlas::addTexture(Texture2D &texture, int slot)
{
texture.retain();
@ -72,7 +235,7 @@ void FontAtlas::setCommonLineHeight(float newHeight)
_commonLineHeight = newHeight;
}
Font & FontAtlas::getFont() const
const Font * FontAtlas::getFont() const
{
return _font;
}

View File

@ -63,21 +63,32 @@ public:
void addLetterDefinition(const FontLetterDefinition &letterDefinition);
bool getLetterDefinitionForChar(unsigned short letteCharUTF16, FontLetterDefinition &outDefinition);
bool prepareLetterDefinitions(unsigned short *utf16String);
void addTexture(Texture2D &texture, int slot);
float getCommonLineHeight() const;
void setCommonLineHeight(float newHeight);
Texture2D & getTexture(int slot);
Font & getFont() const;
const Font * getFont() const;
private:
bool renderCharAt(unsigned short int charToRender, int posX, int posY, unsigned char *destMemory, int destSize);
void relaseTextures();
std::map<int, Texture2D *> _atlasTextures;
std::map<unsigned short, FontLetterDefinition> _fontLetterDefinitions;
float _commonLineHeight;
Font & _font;
Font * _font;
// Dynamic GlyphCollection related stuff
int _currentPage;
unsigned char *_currentPageData;
int _currentPageDataSize;
float _currentPageOrigX;
float _currentPageOrigY;
float _currentPageLineHeight;
float _letterPadding;
};

View File

@ -16,11 +16,6 @@ NS_CC_BEGIN
FontAtlas * FontAtlasFactory::createAtlasFromTTF(const char* fntFilePath, int fontSize, GlyphCollection glyphs, const char *customGlyphs)
{
if( glyphs == GlyphCollection::DYNAMIC )
{
log("ERROR: GlyphCollection::DYNAMIC is not supported yet!");
return nullptr;
}
Font *font = Font::createWithTTF(fntFilePath, fontSize, glyphs, customGlyphs);
if (font)
@ -34,9 +29,14 @@ FontAtlas * FontAtlasFactory::createAtlasFromFNT(const char* fntFilePath)
Font *font = Font::createWithFNT(fntFilePath);
if(font)
return font->createFontAtlas();
{
FontAtlas * atlas = font->createFontAtlas();
return atlas;
}
else
{
return nullptr;
}
}
NS_CC_END

View File

@ -49,6 +49,7 @@ FontDefinitionTTF* FontDefinitionTTF::create(Font *font, int textureSize)
if (ret->initDefinition(font, glyph, textureSize))
{
ret->autorelease();
return ret;
}
else

View File

@ -32,14 +32,13 @@ FontFNT * FontFNT::create(const char* fntFilePath)
delete newConf;
return nullptr;
}
tempFont->autorelease();
return tempFont;
}
FontFNT::~FontFNT()
{
if (_configuration)
_configuration->release();
}
Size * FontFNT::getAdvancesForTextUTF16(unsigned short *text, int &outNumLetters) const
@ -176,7 +175,7 @@ FontAtlas * FontFNT::createFontAtlas()
tempDefinition.anchorX = 0.5f;
tempDefinition.anchorY = 0.5f;
tempDefinition.validDefinition = true;
// add the new definition
tempAtlas->addLetterDefinition(tempDefinition);
}

View File

@ -1,28 +1,29 @@
/****************************************************************************
Copyright (c) 2013 Zynga Inc.
http://www.cocos2d-x.org
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.
****************************************************************************/
Copyright (c) 2013 Zynga Inc.
http://www.cocos2d-x.org
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.
****************************************************************************/
#include <stdio.h>
#include <algorithm>
#include "ccUTF8.h"
#include "CCFontFreeType.h"
@ -38,14 +39,12 @@ bool FontFreeType::_FTInitialized = false;
FontFreeType * FontFreeType::create(const std::string &fontName, int fontSize, GlyphCollection glyphs, const char *customGlyphs)
{
if( glyphs == GlyphCollection::DYNAMIC )
{
log("ERROR: GlyphCollection::DYNAMIC is not supported yet!");
return nullptr;
}
FontFreeType *tempFont = new FontFreeType();
bool dynamicGlyphCollection = false;
if(glyphs == GlyphCollection::DYNAMIC)
dynamicGlyphCollection = true;
FontFreeType *tempFont = new FontFreeType(dynamicGlyphCollection);
if (!tempFont)
return nullptr;
@ -56,7 +55,6 @@ FontFreeType * FontFreeType::create(const std::string &fontName, int fontSize, G
delete tempFont;
return nullptr;
}
return tempFont;
}
@ -79,6 +77,7 @@ void FontFreeType::shutdownFreeType()
if (_FTInitialized == true)
{
FT_Done_FreeType(_FTlibrary);
_FTInitialized = false;
}
}
@ -88,34 +87,35 @@ FT_Library FontFreeType::getFTLibrary()
return _FTlibrary;
}
FontFreeType::FontFreeType() : _letterPadding(5)
FontFreeType::FontFreeType(bool dynamicGlyphCollection)
: _letterPadding(5),
_ttfData(nullptr),
_dynamicGlyphCollection(dynamicGlyphCollection),
_fontRef(nullptr)
{
}
bool FontFreeType::createFontObject(const std::string &fontName, int fontSize)
{
int dpi = 72;
int len = 0;
unsigned char* data = FileUtils::getInstance()->getFileData(fontName.c_str(), "rb", (unsigned long *)(&len));
if (!data)
return false;
// create the new face
FT_Face face;
// create the face from the data
if (FT_New_Memory_Face(getFTLibrary(), data, len, 0, &face ))
int len = 0;
_ttfData = FileUtils::getInstance()->getFileData(fontName.c_str(), "rb", (unsigned long *)(&len));
if (!_ttfData)
return false;
// create the face from the data
if (FT_New_Memory_Face(getFTLibrary(), _ttfData, len, 0, &face ))
return false;
//we want to use unicode
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE))
return false;
// set the requested font size
int fontSizePoints = (int)(64.f * fontSize);
if (FT_Set_Char_Size(face, fontSizePoints, fontSizePoints, dpi, dpi))
int dpi = 72;
int fontSizePoints = (int)(64.f * fontSize);
if (FT_Set_Char_Size(face, fontSizePoints, fontSizePoints, dpi, dpi))
return false;
// store the face globally
@ -130,22 +130,36 @@ bool FontFreeType::createFontObject(const std::string &fontName, int fontSize)
FontFreeType::~FontFreeType()
{
// release the font
// TO DO
if (_fontRef)
{
FT_Done_Face(_fontRef);
}
if (_ttfData)
{
delete _ttfData;
_ttfData = nullptr;
}
}
FontAtlas * FontFreeType::createFontAtlas()
{
FontDefinitionTTF *def = FontDefinitionTTF::create(this);
if (!def)
return nullptr;
FontAtlas *atlas = def->createFontAtlas();
// release the font definition, we don't need it anymore
def->release();
return atlas;
if (_dynamicGlyphCollection)
{
FontAtlas *atlas = new FontAtlas(*this);
this->release();
return atlas;
}
else
{
FontDefinitionTTF *def = FontDefinitionTTF::create(this);
if (!def)
return nullptr;
FontAtlas *atlas = def->createFontAtlas();
return atlas;
}
}
bool FontFreeType::getBBOXFotChar(unsigned short theChar, Rect &outRect) const

View File

@ -39,7 +39,9 @@ class CC_DLL FontFreeType : public Font
public:
static FontFreeType * create(const std::string &fontName, int fontSize, GlyphCollection glyphs, const char *customGlyphs);
static void shutdownFreeType();
virtual FontAtlas * createFontAtlas() override;
virtual Size * getAdvancesForTextUTF16(unsigned short *text, int &outNumLetters) const override;
virtual GlyphDef * getGlyphDefintionsForText(const char *text, int &outNumGlyphs, bool UTF16text = false) const override;
@ -47,20 +49,21 @@ public:
virtual int getFontMaxHeight() const override;
virtual int getLetterPadding() const override;
bool getBBOXFotChar(unsigned short theChar, Rect &outRect) const;
inline bool isDynamicGlyphCollection() { return _dynamicGlyphCollection;}
protected:
FontFreeType();
FontFreeType(bool dynamicGlyphCollection = false);
virtual ~FontFreeType();
bool createFontObject(const std::string &fontName, int fontSize);
private:
bool initFreeType();
void shutdownFreeType();
FT_Library getFTLibrary();
bool getBBOXFotChar(unsigned short theChar, Rect &outRect) const;
int getAdvanceForChar(unsigned short theChar) const;
int getBearingXForChar(unsigned short theChar) const;
int getHorizontalKerningForChars(unsigned short firstChar, unsigned short secondChar) const;
@ -70,7 +73,8 @@ private:
FT_Face _fontRef;
const int _letterPadding;
std::string _fontName;
unsigned char* _ttfData;
bool _dynamicGlyphCollection;
};
NS_CC_END

View File

@ -46,8 +46,6 @@ Label* Label::createWithTTF( const char* label, const char* fontFilePath, int fo
}
return nullptr;
return 0;
}
Label* Label::createWithBMFont( const char* label, const char* bmfontFilePath, TextHAlignment alignment, int lineSize)
@ -95,8 +93,8 @@ Label* Label::createWithAtlas(FontAtlas *atlas, TextHAlignment alignment, int li
}
Label::Label(FontAtlas *atlas, TextHAlignment alignment)
: _currentUTF8String(0)
, _originalUTF8String(0)
: _currentUTF16String(0)
, _originalUTF16String(0)
, _fontAtlas(atlas)
, _alignment(alignment)
, _lineBreakWithoutSpaces(false)
@ -107,32 +105,32 @@ Label::Label(FontAtlas *atlas, TextHAlignment alignment)
, _cascadeOpacityEnabled(true)
, _displayedOpacity(255)
, _realOpacity(255)
, _isOpacityModifyRGB(false)
, _isOpacityModifyRGB(true)
,_reusedLetter(nullptr)
{
}
Label::~Label()
{
CC_SAFE_RELEASE(_spriteArray);
CC_SAFE_RELEASE(_spriteArrayCache);
if (_currentUTF8String)
delete [] _currentUTF8String;
if (_advances)
delete [] _advances;
{
delete [] _currentUTF16String;
delete [] _originalUTF16String;
delete [] _advances;
if (_fontAtlas)
FontAtlasCache::releaseFontAtlas(_fontAtlas);
delete _reusedLetter;
}
bool Label::init()
{
_spriteArray = Array::createWithCapacity(30);
_spriteArrayCache = Array::createWithCapacity(30);
_spriteArray->retain();
_spriteArrayCache->retain();
{
if(_fontAtlas)
{
_reusedLetter = new Sprite;
_reusedLetter->initWithTexture(&_fontAtlas->getTexture(0));
_reusedLetter->setOpacityModifyRGB(_isOpacityModifyRGB);
return SpriteBatchNode::initWithTexture(&_fontAtlas->getTexture(0), 30);
}
return true;
}
@ -151,14 +149,10 @@ bool Label::setText(const char *stringToRender, float lineWidth, TextHAlignment
// reset the string
resetCurrentString();
_width = lineWidth;
_alignment = alignment;
_lineBreakWithoutSpaces = lineBreakWithoutSpaces;
// release all the sprites
moveAllSpritesToCache();
// store locally common line height
_commonLineHeight = _fontAtlas->getCommonLineHeight();
if (_commonLineHeight <= 0)
@ -169,11 +163,8 @@ bool Label::setText(const char *stringToRender, float lineWidth, TextHAlignment
if(!utf16String)
return false;
numLetter = cc_wcslen(utf16String);
SpriteBatchNode::initWithTexture(&_fontAtlas->getTexture(0), numLetter);
_cascadeColorEnabled = true;
//
setCurrentString(utf16String);
setOriginalString(utf16String);
@ -247,30 +238,55 @@ void Label::setScaleY(float scaleY)
}
void Label::alignText()
{
hideAllLetters();
LabelTextFormatter::createStringSprites(this);
if( LabelTextFormatter::multilineText(this) )
{
hideAllLetters();
{
if(_textureAtlas)
_textureAtlas->removeAllQuads();
_fontAtlas->prepareLetterDefinitions(_currentUTF16String);
LabelTextFormatter::createStringSprites(this);
if( LabelTextFormatter::multilineText(this) )
LabelTextFormatter::createStringSprites(this);
}
LabelTextFormatter::alignText(this);
}
void Label::hideAllLetters()
{
Object* Obj = NULL;
CCARRAY_FOREACH(_spriteArray, Obj)
int strLen = cc_wcslen(_currentUTF16String);
if (_children && _children->count() != 0)
{
((Sprite *)Obj)->setVisible(false);
for (auto child: *_children)
{
Node* pNode = static_cast<Node*>( child );
if (pNode)
{
int tag = pNode->getTag();
if(tag < 0 || tag >= strLen)
SpriteBatchNode::removeChild(pNode, true);
}
}
}
CCARRAY_FOREACH(_spriteArrayCache, Obj)
{
((Sprite *)Obj)->setVisible(false);
_reusedLetter->setBatchNode(nullptr);
int vaildIndex = 0;
Sprite* child = nullptr;
Rect uvRect;
for (int ctr = 0; ctr < strLen; ++ctr)
{
if (_lettersInfo[ctr].def.validDefinition)
{
child = static_cast<Sprite*>( this->getChildByTag(ctr) );
if (child)
{
uvRect.size.height = _lettersInfo[ctr].def.height;
uvRect.size.width = _lettersInfo[ctr].def.width;
uvRect.origin.x = _lettersInfo[ctr].def.U;
uvRect.origin.y = _lettersInfo[ctr].def.V;
child->setTexture(&_fontAtlas->getTexture(_lettersInfo[ctr].def.textureID));
child->setTextureRect(uvRect);
}
updateSpriteWithLetterDefinition(_reusedLetter,_lettersInfo[ctr].def,&_fontAtlas->getTexture(_lettersInfo[ctr].def.textureID));
_reusedLetter->setPosition(_lettersInfo[ctr].position);
insertQuadFromSprite(_reusedLetter,vaildIndex++);
}
}
}
@ -282,10 +298,8 @@ bool Label::computeAdvancesForString(unsigned short int *stringToRender)
_advances = 0;
}
Font &theFont = _fontAtlas->getFont();
int letterCount = 0;
_advances = theFont.getAdvancesForTextUTF16(stringToRender, letterCount);
_advances = _fontAtlas->getFont()->getAdvancesForTextUTF16(stringToRender, letterCount);
if(!_advances)
return false;
@ -295,17 +309,17 @@ bool Label::computeAdvancesForString(unsigned short int *stringToRender)
bool Label::setOriginalString(unsigned short *stringToSet)
{
if (_originalUTF8String)
if (_originalUTF16String)
{
delete [] _originalUTF8String;
_originalUTF8String = 0;
delete [] _originalUTF16String;
_originalUTF16String = 0;
}
int newStringLenght = cc_wcslen(stringToSet);
_originalUTF8String = new unsigned short int [newStringLenght + 1];
memset(_originalUTF8String, 0, (newStringLenght + 1) * 2);
memcpy(_originalUTF8String, stringToSet, (newStringLenght * 2));
_originalUTF8String[newStringLenght] = 0;
_originalUTF16String = new unsigned short int [newStringLenght + 1];
memset(_originalUTF16String, 0, (newStringLenght + 1) * 2);
memcpy(_originalUTF16String, stringToSet, (newStringLenght * 2));
_originalUTF16String[newStringLenght] = 0;
return true;
}
@ -313,65 +327,36 @@ bool Label::setOriginalString(unsigned short *stringToSet)
bool Label::setCurrentString(unsigned short *stringToSet)
{
// set the new string
if (_currentUTF8String)
if (_currentUTF16String)
{
delete [] _currentUTF8String;
_currentUTF8String = 0;
delete [] _currentUTF16String;
_currentUTF16String = 0;
}
//
_currentUTF8String = stringToSet;
_currentUTF16String = stringToSet;
// compute the advances
return computeAdvancesForString(stringToSet);
}
void Label::resetCurrentString()
{
if ((!_currentUTF8String) && (!_originalUTF8String))
if ((!_currentUTF16String) && (!_originalUTF16String))
return;
// set the new string
if (_currentUTF8String)
if (_currentUTF16String)
{
delete [] _currentUTF8String;
_currentUTF8String = 0;
delete [] _currentUTF16String;
_currentUTF16String = 0;
}
int stringLenght = cc_wcslen(_originalUTF8String);
_currentUTF8String = new unsigned short int [stringLenght + 1];
memcpy(_currentUTF8String, _originalUTF8String, stringLenght * 2);
_currentUTF8String[stringLenght] = 0;
int stringLenght = cc_wcslen(_originalUTF16String);
_currentUTF16String = new unsigned short int [stringLenght + 1];
memcpy(_currentUTF16String, _originalUTF16String, stringLenght * 2);
_currentUTF16String[stringLenght] = 0;
}
Sprite * Label::createNewSpriteFromLetterDefinition(const FontLetterDefinition &theDefinition, Texture2D *theTexture)
{
Rect uvRect;
uvRect.size.height = theDefinition.height;
uvRect.size.width = theDefinition.width;
uvRect.origin.x = theDefinition.U;
uvRect.origin.y = theDefinition.V;
SpriteFrame *pFrame = SpriteFrame::createWithTexture(theTexture, uvRect);
Sprite *tempSprite = getSprite();
if (!tempSprite)
return 0;
tempSprite->initWithSpriteFrame(pFrame);
tempSprite->setAnchorPoint(Point(theDefinition.anchorX, theDefinition.anchorY));
tempSprite->setBatchNode(this);
// Apply label properties
tempSprite->setOpacityModifyRGB(_isOpacityModifyRGB);
// Color MUST be set before opacity, since opacity might change color if OpacityModifyRGB is on
tempSprite->updateDisplayedColor(_displayedColor);
tempSprite->updateDisplayedOpacity(_displayedOpacity);
return tempSprite;
}
Sprite * Label::updateSpriteWithLetterDefinition(Sprite *spriteToUpdate, const FontLetterDefinition &theDefinition, Texture2D *theTexture)
{
if (!spriteToUpdate)
@ -389,143 +374,93 @@ Sprite * Label::updateSpriteWithLetterDefinition(Sprite *spriteToUpdate, const F
SpriteFrame *frame = SpriteFrame::createWithTexture(theTexture, uvRect);
if (frame)
{
spriteToUpdate->setBatchNode(this);
spriteToUpdate->setTexture(theTexture);
spriteToUpdate->setDisplayFrame(frame);
spriteToUpdate->setAnchorPoint(Point(theDefinition.anchorX, theDefinition.anchorY));
spriteToUpdate->setBatchNode(this);
}
spriteToUpdate->setAnchorPoint(Point(theDefinition.anchorX, theDefinition.anchorY));
}
return spriteToUpdate;
}
}
Sprite * Label::getSpriteForLetter(unsigned short int newLetter)
bool Label::recordLetterInfo(const cocos2d::Point& point,unsigned short int theChar, int spriteIndex)
{
if (!_fontAtlas)
return 0;
if (spriteIndex >= _lettersInfo.size())
{
LetterInfo tmpInfo;
_lettersInfo.push_back(tmpInfo);
}
_fontAtlas->getLetterDefinitionForChar(theChar, _lettersInfo[spriteIndex].def);
_lettersInfo[spriteIndex].position = point;
_lettersInfo[spriteIndex].contentSize.width = _lettersInfo[spriteIndex].def.width;
_lettersInfo[spriteIndex].contentSize.height = _lettersInfo[spriteIndex].def.height;
return _lettersInfo[spriteIndex].def.validDefinition;
}
bool Label::recordPlaceholderInfo(int spriteIndex)
{
if (spriteIndex >= _lettersInfo.size())
{
LetterInfo tmpInfo;
_lettersInfo.push_back(tmpInfo);
}
_lettersInfo[spriteIndex].def.validDefinition = false;
FontLetterDefinition tempDefinition;
bool validDefinition = _fontAtlas->getLetterDefinitionForChar(newLetter, tempDefinition);
if (validDefinition)
{
Sprite *newSprite = createNewSpriteFromLetterDefinition(tempDefinition, &_fontAtlas->getTexture(tempDefinition.textureID) );
this->addChild(newSprite);
return newSprite;
}
else
{
return 0;
}
return false;
}
Sprite * Label::updateSpriteForLetter(Sprite *spriteToUpdate, unsigned short int newLetter)
void Label::addChild(Node * child, int zOrder/* =0 */, int tag/* =0 */)
{
if (!spriteToUpdate || !_fontAtlas)
return 0;
else
{
FontLetterDefinition tempDefinition;
bool validDefinition = _fontAtlas->getLetterDefinitionForChar(newLetter, tempDefinition);
if (validDefinition)
{
Sprite *pNewSprite = updateSpriteWithLetterDefinition(spriteToUpdate, tempDefinition, &_fontAtlas->getTexture(tempDefinition.textureID) );
return pNewSprite;
}
else
{
return 0;
}
}
}
void Label::moveAllSpritesToCache()
{
Object* pObj = NULL;
CCARRAY_FOREACH(_spriteArray, pObj)
{
((Sprite *)pObj)->removeFromParent();
_spriteArrayCache->addObject(pObj);
}
_spriteArray->removeAllObjects();
}
Sprite * Label::getSprite()
{
if (_spriteArrayCache->count())
{
Sprite *retSprite = static_cast<Sprite *>(_spriteArrayCache->getLastObject());
_spriteArrayCache->removeLastObject();
return retSprite;
}
else
{
Sprite *retSprite = new Sprite;
return retSprite;
}
CCASSERT(0, "addChild: is not supported on Label.");
}
///// PROTOCOL STUFF
Sprite * Label::getSpriteChild(int ID) const
Sprite * Label::getLetter(int ID)
{
Object* pObj = NULL;
CCARRAY_FOREACH(_spriteArray, pObj)
{
Sprite *pSprite = (Sprite *)pObj;
if ( pSprite->getTag() == ID)
if (ID < getStringLenght())
{
if(_lettersInfo[ID].def.validDefinition == false)
return nullptr;
Sprite* sp = static_cast<Sprite*>(this->getChildByTag(ID));
if (!sp)
{
return pSprite;
Rect uvRect;
uvRect.size.height = _lettersInfo[ID].def.height;
uvRect.size.width = _lettersInfo[ID].def.width;
uvRect.origin.x = _lettersInfo[ID].def.U;
uvRect.origin.y = _lettersInfo[ID].def.V;
sp = new Sprite();
sp->initWithTexture(&_fontAtlas->getTexture(_lettersInfo[ID].def.textureID),uvRect);
sp->setBatchNode(this);
sp->setAnchorPoint(Point(_lettersInfo[ID].def.anchorX, _lettersInfo[ID].def.anchorY));
sp->setPosition(_lettersInfo[ID].position);
sp->setOpacity(_realOpacity);
this->addSpriteWithoutQuad(sp, ID, ID);
sp->release();
}
}
return 0;
}
Array* Label::getChildrenLetters() const
{
return _spriteArray;
}
Sprite * Label::getSpriteForChar(unsigned short int theChar, int spriteIndexHint)
{
// ret sprite
Sprite *retSprite = 0;
// look for already existing sprites
retSprite = getSpriteChild(spriteIndexHint);
if (!retSprite)
{
retSprite = getSpriteForLetter(theChar);
if (!retSprite)
return 0;
if (retSprite)
retSprite->setTag(spriteIndexHint);
_spriteArray->addObject(retSprite);
return sp;
}
// the sprite is now visible
retSprite->setVisible(true);
// set the right texture letter to the sprite
updateSpriteForLetter(retSprite, theChar);
// we are done here
return retSprite;
return nullptr;
}
float Label::getLetterPosXLeft( Sprite* sp ) const
float Label::getLetterPosXLeft( int index ) const
{
float scaleX = _scaleX;
return sp->getPosition().x * scaleX - (sp->getContentSize().width * scaleX * sp->getAnchorPoint().x);
return _lettersInfo[index].position.x * _scaleX - (_lettersInfo[index].contentSize.width * _scaleX * _lettersInfo[index].def.anchorX);
}
float Label::getLetterPosXRight( Sprite* sp ) const
float Label::getLetterPosXRight( int index ) const
{
float scaleX = _scaleX;
return sp->getPosition().x * scaleX + (sp->getContentSize().width * scaleX * sp->getAnchorPoint().x);
return _lettersInfo[index].position.x * _scaleX + (_lettersInfo[index].contentSize.width * _scaleX * _lettersInfo[index].def.anchorX);
}
int Label::getCommonLineHeight() const
@ -578,7 +513,7 @@ int Label::getAdvanceForChar(unsigned short c, int hintPositionInString) const
Rect Label::getRectForChar(unsigned short c) const
{
return _fontAtlas->getFont().getRectForChar(c);
return _fontAtlas->getFont()->getRectForChar(c);
}
// string related stuff
@ -586,14 +521,14 @@ int Label::getStringNumLines() const
{
int quantityOfLines = 1;
unsigned int stringLen = _currentUTF8String ? cc_wcslen(_currentUTF8String) : 0;
unsigned int stringLen = _currentUTF16String ? cc_wcslen(_currentUTF16String) : 0;
if (stringLen == 0)
return (-1);
// count number of lines
for (unsigned int i = 0; i < stringLen - 1; ++i)
{
unsigned short c = _currentUTF8String[i];
unsigned short c = _currentUTF16String[i];
if (c == '\n')
{
quantityOfLines++;
@ -605,17 +540,17 @@ int Label::getStringNumLines() const
int Label::getStringLenght() const
{
return _currentUTF8String ? cc_wcslen(_currentUTF8String) : 0;
return _currentUTF16String ? cc_wcslen(_currentUTF16String) : 0;
}
unsigned short Label::getCharAtStringPosition(int position) const
{
return _currentUTF8String[position];
return _currentUTF16String[position];
}
unsigned short * Label::getUTF8String() const
{
return _currentUTF8String;
return _currentUTF16String;
}
void Label::assignNewUTF8String(unsigned short *newString)
@ -663,8 +598,7 @@ void Label::setOpacityModifyRGB(bool isOpacityModifyRGB)
_isOpacityModifyRGB = isOpacityModifyRGB;
if (_children && _children->count() != 0)
{
Object* child;
CCARRAY_FOREACH(_children, child)
for (auto child: *_children)
{
Node* pNode = static_cast<Node*>( child );
if (pNode)
@ -677,6 +611,7 @@ void Label::setOpacityModifyRGB(bool isOpacityModifyRGB)
}
}
}
_reusedLetter->setOpacityModifyRGB(true);
}
unsigned char Label::getOpacity() const
@ -692,7 +627,7 @@ unsigned char Label::getDisplayedOpacity() const
void Label::setOpacity(GLubyte opacity)
{
_displayedOpacity = _realOpacity = opacity;
_reusedLetter->setOpacity(opacity);
if( _cascadeOpacityEnabled ) {
GLubyte parentOpacity = 255;
RGBAProtocol* pParent = dynamic_cast<RGBAProtocol*>(_parent);
@ -707,12 +642,28 @@ void Label::updateDisplayedOpacity(GLubyte parentOpacity)
{
_displayedOpacity = _realOpacity * parentOpacity/255.0;
Object* pObj;
CCARRAY_FOREACH(_children, pObj)
for (auto child: *_children)
{
Sprite *item = static_cast<Sprite*>( pObj );
Sprite *item = static_cast<Sprite*>( child );
item->updateDisplayedOpacity(_displayedOpacity);
}
V3F_C4B_T2F_Quad *quads = _textureAtlas->getQuads();
int count = _textureAtlas->getTotalQuads();
Color4B color4( _displayedColor.r, _displayedColor.g, _displayedColor.b, _displayedOpacity );
if (_isOpacityModifyRGB)
{
color4.r *= _displayedOpacity/255.0f;
color4.g *= _displayedOpacity/255.0f;
color4.b *= _displayedOpacity/255.0f;
}
for (int index = 0; index < count; ++index)
{
quads[index].bl.colors = color4;
quads[index].br.colors = color4;
quads[index].tl.colors = color4;
quads[index].tr.colors = color4;
_textureAtlas->updateQuad(&quads[index], index);
}
}
bool Label::isCascadeOpacityEnabled() const
@ -738,7 +689,7 @@ const Color3B& Label::getDisplayedColor() const
void Label::setColor(const Color3B& color)
{
_displayedColor = _realColor = color;
_reusedLetter->setColor(color);
if( _cascadeColorEnabled )
{
Color3B parentColor = Color3B::WHITE;
@ -757,12 +708,31 @@ void Label::updateDisplayedColor(const Color3B& parentColor)
_displayedColor.g = _realColor.g * parentColor.g/255.0;
_displayedColor.b = _realColor.b * parentColor.b/255.0;
Object* pObj;
CCARRAY_FOREACH(_children, pObj)
for (auto child: *_children)
{
Sprite *item = static_cast<Sprite*>( pObj );
Sprite *item = static_cast<Sprite*>( child );
item->updateDisplayedColor(_displayedColor);
}
V3F_C4B_T2F_Quad *quads = _textureAtlas->getQuads();
int count = _textureAtlas->getTotalQuads();
Color4B color4( _displayedColor.r, _displayedColor.g, _displayedColor.b, _displayedOpacity );
// special opacity for premultiplied textures
if (_isOpacityModifyRGB)
{
color4.r *= _displayedOpacity/255.0f;
color4.g *= _displayedOpacity/255.0f;
color4.b *= _displayedOpacity/255.0f;
}
for (int index=0; index<count; ++index)
{
quads[index].bl.colors = color4;
quads[index].br.colors = color4;
quads[index].tl.colors = color4;
quads[index].tr.colors = color4;
_textureAtlas->updateQuad(&quads[index], index);
}
}
bool Label::isCascadeColorEnabled() const

View File

@ -82,12 +82,13 @@ public:
virtual unsigned char getDisplayedOpacity() const override;
// CCLabelTextFormat protocol implementation
virtual Sprite * getSpriteChild(int ID) const override;
virtual Array * getChildrenLetters() const override;
virtual Sprite * getSpriteForChar(unsigned short int theChar, int spriteIndexHint) override;
virtual float getLetterPosXLeft( Sprite* sp ) const override;
virtual float getLetterPosXRight( Sprite* sp ) const override;
virtual std::vector<LetterInfo> *getLettersInfo() override { return &_lettersInfo; };
virtual bool recordLetterInfo(const cocos2d::Point& point,unsigned short int theChar, int spriteIndex) override;
virtual bool recordPlaceholderInfo(int spriteIndex) override;
virtual float getLetterPosXLeft( int index ) const override;
virtual float getLetterPosXRight( int index ) const override;
virtual Sprite * getLetter(int ID) override;
// font related stuff
virtual int getCommonLineHeight() const override;
@ -113,7 +114,8 @@ public:
// carloX
const char * getString() const { return "not implemented"; }
void addChild(Node * child, int zOrder=0, int tag=0);
private:
/**
* @js NA
@ -129,29 +131,26 @@ private:
bool init();
void alignText();
void hideAllLetters();
void moveAllSpritesToCache();
void alignText();
bool computeAdvancesForString(unsigned short int *stringToRender);
bool setCurrentString(unsigned short *stringToSet);
bool setOriginalString(unsigned short *stringToSet);
void resetCurrentString();
Sprite * updateSpriteWithLetterDefinition(Sprite *spriteToUpdate, const FontLetterDefinition &theDefinition, Texture2D *theTexture);
Sprite * getSprite();
Sprite * createNewSpriteFromLetterDefinition(const FontLetterDefinition &theDefinition, Texture2D *theTexture);
Sprite * updateSpriteWithLetterDefinition(Sprite *spriteToUpdate, const FontLetterDefinition &theDefinition, Texture2D *theTexture);
Sprite * getSpriteForLetter(unsigned short int newLetter);
Sprite * updateSpriteForLetter(Sprite *spriteToUpdate, unsigned short int newLetter);
Array * _spriteArray;
Array * _spriteArrayCache;
//! used for optimization
Sprite *_reusedLetter;
std::vector<LetterInfo> _lettersInfo;
float _commonLineHeight;
bool _lineBreakWithoutSpaces;
float _width;
TextHAlignment _alignment;
unsigned short int * _currentUTF8String;
unsigned short int * _originalUTF8String;
unsigned short int * _currentUTF16String;
unsigned short int * _originalUTF16String;
Size * _advances;
FontAtlas * _fontAtlas;
Color3B _displayedColor;

View File

@ -24,19 +24,31 @@
#ifndef _CCLabelTextFormatProtocol_h_
#define _CCLabelTextFormatProtocol_h_
#include "CCFontAtlas.h"
#include <vector>
NS_CC_BEGIN
struct LetterInfo
{
FontLetterDefinition def;
Point position;
Size contentSize;
bool visible;
};
class CC_DLL LabelTextFormatProtocol
{
public:
virtual bool recordLetterInfo(const cocos2d::Point& point,unsigned short int theChar, int spriteIndex) = 0;
virtual bool recordPlaceholderInfo(int spriteIndex) = 0;
virtual std::vector<LetterInfo> *getLettersInfo() = 0;
virtual float getLetterPosXLeft(int index) const = 0;
virtual float getLetterPosXRight(int index) const = 0;
// sprite related stuff
virtual cocos2d::Sprite *getSpriteChild(int ID) const = 0;
virtual cocos2d::Array *getChildrenLetters() const = 0;
virtual cocos2d::Sprite *getSpriteForChar(unsigned short int theChar, int spriteIndexHint) = 0;
virtual float getLetterPosXLeft(cocos2d::Sprite* sp) const = 0;
virtual float getLetterPosXRight(cocos2d::Sprite* sp) const = 0;
virtual cocos2d::Sprite *getLetter(int ID) = 0;
// font related stuff
virtual int getCommonLineHeight() const = 0;

View File

@ -53,23 +53,24 @@ bool LabelTextFormatter::multilineText(LabelTextFormatProtocol *theLabel)
float startOfLine = -1, startOfWord = -1;
int skip = 0;
Array* children = theLabel->getChildrenLetters();
for (int j = 0; j < children->count(); j++)
{
Sprite* characterSprite;
unsigned int justSkipped = 0;
int strLen = theLabel->getStringLenght();
std::vector<LetterInfo> *leterInfo = theLabel->getLettersInfo();
int tIndex = 0;
for (int j = 0; j < strLen; j++)
{
LetterInfo* info = &leterInfo->at(j+skip);
unsigned int justSkipped = 0;
while (!(characterSprite = theLabel->getSpriteChild(j + skip + justSkipped)))
while (info->def.validDefinition == false)
{
justSkipped++;
info = &leterInfo->at( j+skip+justSkipped );
}
skip += justSkipped;
if (!characterSprite->isVisible())
continue;
tIndex = j + skip;
if (i >= stringLength)
break;
@ -78,7 +79,7 @@ bool LabelTextFormatter::multilineText(LabelTextFormatProtocol *theLabel)
if (!isStartOfWord)
{
startOfWord = theLabel->getLetterPosXLeft( characterSprite );
startOfWord = theLabel->getLetterPosXLeft( tIndex );
isStartOfWord = true;
}
@ -110,7 +111,7 @@ bool LabelTextFormatter::multilineText(LabelTextFormatProtocol *theLabel)
if (!startOfWord)
{
startOfWord = theLabel->getLetterPosXLeft( characterSprite );
startOfWord = theLabel->getLetterPosXLeft( tIndex );
isStartOfWord = true;
}
if (!startOfLine)
@ -133,7 +134,7 @@ bool LabelTextFormatter::multilineText(LabelTextFormatProtocol *theLabel)
}
// Out of bounds.
if (theLabel->getLetterPosXRight( characterSprite ) - startOfLine > theLabel->getMaxLineWidth())
if (theLabel->getLetterPosXRight( tIndex ) - startOfLine > theLabel->getMaxLineWidth())
{
if (!theLabel->breakLineWithoutSpace())
{
@ -171,7 +172,7 @@ bool LabelTextFormatter::multilineText(LabelTextFormatProtocol *theLabel)
if (!startOfWord)
{
startOfWord = theLabel->getLetterPosXLeft( characterSprite );
startOfWord = theLabel->getLetterPosXLeft( tIndex );
isStartOfWord = true;
}
if (!startOfLine)
@ -222,9 +223,10 @@ bool LabelTextFormatter::alignText(LabelTextFormatProtocol *theLabel)
int lineNumber = 0;
int strLen = cc_wcslen(theLabel->getUTF8String());
vector<unsigned short> lastLine;
std::vector<LetterInfo> *leterInfo = theLabel->getLettersInfo();
for (int ctr = 0; ctr <= strLen; ++ctr)
{
unsigned short int currentChar = theLabel->getCharAtStringPosition(ctr);
unsigned short int currentChar = theLabel->getCharAtStringPosition(ctr);
if (currentChar == '\n' || currentChar == 0)
{
@ -240,11 +242,12 @@ bool LabelTextFormatter::alignText(LabelTextFormatProtocol *theLabel)
int index = i + lineLength - 1 + lineNumber;
if (index < 0) continue;
Sprite* lastChar = theLabel->getSpriteChild(index);
if (lastChar == nullptr)
if(currentChar == 0)
continue;
lineWidth = lastChar->getPosition().x + lastChar->getContentSize().width / 2.0f;
LetterInfo* info = &leterInfo->at( index );
if(info->def.validDefinition == false)
continue;
lineWidth = info->position.x + info->contentSize.width /2.0f;
float shift = 0;
switch (theLabel->getTextAlignment())
@ -266,10 +269,11 @@ bool LabelTextFormatter::alignText(LabelTextFormatProtocol *theLabel)
index = i + j + lineNumber;
if (index < 0) continue;
Sprite* characterSprite = theLabel->getSpriteChild(index);
if (characterSprite)
characterSprite->setPosition( characterSprite->getPosition() + Point(shift, 0.0f));
info = &leterInfo->at( index );
if(info)
{
info->position = info->position + Point(shift, 0.0f);
}
}
}
@ -336,15 +340,8 @@ bool LabelTextFormatter::createStringSprites(LabelTextFormatProtocol *theLabel)
{
nextFontPositionX = 0;
nextFontPositionY -= commonLineHeight;
continue;
}
// get the sprite to this letter
Sprite *letterSprite = theLabel->getSpriteForChar(c, i);
if (!letterSprite)
{
log("WARNING: can't find letter definition in font file for letter: %c", c);
theLabel->recordPlaceholderInfo(i);
continue;
}
@ -354,10 +351,13 @@ bool LabelTextFormatter::createStringSprites(LabelTextFormatProtocol *theLabel)
Point fontPos = Point((float)nextFontPositionX + charXOffset + charRect.size.width * 0.5f + kerningAmount,
(float)nextFontPositionY + yOffset - charRect.size.height * 0.5f);
// set the sprite position
letterSprite->setPosition(CC_POINT_PIXELS_TO_POINTS(fontPos));
if( theLabel->recordLetterInfo(CC_POINT_PIXELS_TO_POINTS(fontPos),c,i) == false)
{
log("WARNING: can't find letter definition in font file for letter: %c", c);
continue;
}
// update kerning
nextFontPositionX += charAdvance + kerningAmount;
prev = c;

View File

@ -264,9 +264,9 @@ LabelFNTSpriteActions::LabelFNTSpriteActions()
label->setAnchorPoint( Point(0.5f, 0.5f) );
auto BChar = (Sprite*) label->getChildByTag(0);
auto FChar = (Sprite*) label->getChildByTag(7);
auto AChar = (Sprite*) label->getChildByTag(12);
auto BChar = (Sprite*) label->getLetter(0);
auto FChar = (Sprite*) label->getLetter(7);
auto AChar = (Sprite*) label->getLetter(12);
auto rotate = RotateBy::create(2, 360);
@ -296,7 +296,7 @@ LabelFNTSpriteActions::LabelFNTSpriteActions()
addChild(label2, 0, kTagBitmapAtlas2);
label2->setPosition( Point(s.width/2.0f, 80) );
auto lastChar = (Sprite*) label2->getChildByTag(1);
auto lastChar = (Sprite*) label2->getLetter(3);
lastChar->runAction( rot_4ever->clone() );
schedule( schedule_selector(LabelFNTSpriteActions::step), 0.1f);