2011-11-09 22:11:36 +08:00
/****************************************************************************
Copyright ( c ) 2008 - 2010 Ricardo Quesada
2014-01-07 11:25:07 +08:00
Copyright ( c ) 2010 - 2012 cocos2d - x . org
2011-11-09 22:11:36 +08:00
Copyright ( c ) 2011 Zynga Inc .
2014-01-07 11:25:07 +08:00
Copyright ( c ) 2013 - 2014 Chukong Technologies Inc .
2011-11-09 22:11:36 +08:00
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 .
Use any of these editors to generate BMFonts :
http : //glyphdesigner.71squared.com/ (Commercial, Mac OS X)
http : //www.n4te.com/hiero/hiero.jnlp (Free, Java)
http : //slick.cokeandcode.com/demos/hiero.jnlp (Free, Java)
http : //www.angelcode.com/products/bmfont/ (Free, Windows only)
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "CCLabelBMFont.h"
2013-10-14 14:01:00 +08:00
# include "CCString.h"
# include "CCDictionary.h"
2011-11-09 22:11:36 +08:00
# include "CCConfiguration.h"
2013-10-14 14:01:00 +08:00
# include "CCDrawingPrimitives.h"
# include "CCSprite.h"
2012-06-19 16:20:46 +08:00
# include "platform/CCFileUtils.h"
2012-03-22 09:46:07 +08:00
# include "CCDirector.h"
2013-10-14 14:01:00 +08:00
# include "CCTextureCache.h"
# include "ccUTF8.h"
2013-12-11 17:15:27 +08:00
# include "CCMap.h"
2011-11-09 22:11:36 +08:00
2012-04-10 15:14:55 +08:00
using namespace std ;
2012-03-20 15:04:53 +08:00
NS_CC_BEGIN
2013-03-20 13:55:43 +08:00
// The return value needs to be deleted by CC_SAFE_DELETE_ARRAY.
static unsigned short * copyUTF16StringN ( unsigned short * str )
{
int length = str ? cc_wcslen ( str ) : 0 ;
unsigned short * ret = new unsigned short [ length + 1 ] ;
for ( int i = 0 ; i < length ; + + i ) {
ret [ i ] = str [ i ] ;
}
ret [ length ] = 0 ;
return ret ;
}
2012-03-20 15:04:53 +08:00
//
//FNTConfig Cache - free functions
//
2013-12-11 17:15:27 +08:00
static Map < std : : string , CCBMFontConfiguration * > * s_configurations = nullptr ;
2012-06-19 16:31:26 +08:00
2013-11-06 11:02:03 +08:00
CCBMFontConfiguration * FNTConfigLoadFile ( const std : : string & fntFile )
2012-03-20 15:04:53 +08:00
{
2013-12-18 17:47:20 +08:00
CCBMFontConfiguration * ret = nullptr ;
2012-03-20 15:04:53 +08:00
2013-12-11 17:15:27 +08:00
if ( s_configurations = = nullptr )
2012-04-19 14:35:52 +08:00
{
2013-12-11 17:15:27 +08:00
s_configurations = new Map < std : : string , CCBMFontConfiguration * > ( ) ;
2012-04-19 14:35:52 +08:00
}
2010-08-12 17:39:25 +08:00
2013-12-11 17:15:27 +08:00
ret = s_configurations - > at ( fntFile ) ;
2013-12-18 17:47:20 +08:00
if ( ret = = nullptr )
2012-04-19 14:35:52 +08:00
{
2013-11-07 09:05:13 +08:00
ret = CCBMFontConfiguration : : create ( fntFile . c_str ( ) ) ;
if ( ret )
2012-06-08 15:29:47 +08:00
{
2013-12-11 17:15:27 +08:00
s_configurations - > insert ( fntFile , ret ) ;
2012-06-08 15:29:47 +08:00
}
2012-04-19 14:35:52 +08:00
}
2012-01-18 18:02:39 +08:00
2013-11-07 09:05:13 +08:00
return ret ;
2012-03-20 15:04:53 +08:00
}
2012-01-18 18:02:39 +08:00
2012-03-20 15:04:53 +08:00
void FNTConfigRemoveCache ( void )
{
2013-12-11 17:15:27 +08:00
if ( s_configurations )
2012-04-19 14:35:52 +08:00
{
2013-12-11 17:15:27 +08:00
s_configurations - > clear ( ) ;
CC_SAFE_DELETE ( s_configurations ) ;
2012-04-19 14:35:52 +08:00
}
2012-03-20 15:04:53 +08:00
}
2012-03-22 09:46:07 +08:00
2012-03-20 15:04:53 +08:00
//
//BitmapFontConfiguration
//
2013-11-07 09:05:13 +08:00
CCBMFontConfiguration * CCBMFontConfiguration : : create ( const std : : string & FNTfile )
2012-03-20 15:04:53 +08:00
{
2013-11-07 09:05:13 +08:00
CCBMFontConfiguration * ret = new CCBMFontConfiguration ( ) ;
if ( ret - > initWithFNTfile ( FNTfile ) )
2012-04-19 14:35:52 +08:00
{
2013-11-07 09:05:13 +08:00
ret - > autorelease ( ) ;
return ret ;
2012-04-19 14:35:52 +08:00
}
2013-11-07 09:05:13 +08:00
CC_SAFE_DELETE ( ret ) ;
2013-12-18 17:47:20 +08:00
return nullptr ;
2012-03-20 15:04:53 +08:00
}
2013-11-07 09:05:13 +08:00
bool CCBMFontConfiguration : : initWithFNTfile ( const std : : string & FNTfile )
2012-03-20 15:04:53 +08:00
{
2013-12-18 17:47:20 +08:00
_kerningDictionary = nullptr ;
_fontDefDictionary = nullptr ;
2012-11-15 17:16:51 +08:00
2013-06-15 14:03:30 +08:00
_characterSet = this - > parseConfigFile ( FNTfile ) ;
2012-11-15 17:16:51 +08:00
2013-06-15 14:03:30 +08:00
if ( ! _characterSet )
2012-06-08 15:29:47 +08:00
{
return false ;
}
2012-04-19 14:35:52 +08:00
return true ;
2012-03-20 15:04:53 +08:00
}
2012-11-15 17:16:51 +08:00
std : : set < unsigned int > * CCBMFontConfiguration : : getCharacterSet ( ) const
{
2013-06-15 14:03:30 +08:00
return _characterSet ;
2012-11-15 17:16:51 +08:00
}
2012-03-20 15:04:53 +08:00
CCBMFontConfiguration : : CCBMFontConfiguration ( )
2013-12-18 17:47:20 +08:00
: _fontDefDictionary ( nullptr )
2013-06-15 14:03:30 +08:00
, _commonHeight ( 0 )
2013-12-18 17:47:20 +08:00
, _kerningDictionary ( nullptr )
, _characterSet ( nullptr )
2012-03-20 15:04:53 +08:00
{
}
CCBMFontConfiguration : : ~ CCBMFontConfiguration ( )
{
2013-08-22 11:05:06 +08:00
CCLOGINFO ( " deallocing CCBMFontConfiguration: %p " , this ) ;
2012-04-19 14:35:52 +08:00
this - > purgeFontDefDictionary ( ) ;
this - > purgeKerningDictionary ( ) ;
2013-06-15 14:03:30 +08:00
_atlasName . clear ( ) ;
CC_SAFE_DELETE ( _characterSet ) ;
2012-03-20 15:04:53 +08:00
}
2012-03-22 09:46:07 +08:00
2013-12-11 17:15:27 +08:00
std : : string CCBMFontConfiguration : : description ( void ) const
2012-03-20 15:04:53 +08:00
{
2013-12-12 09:37:56 +08:00
return StringUtils : : format (
2013-04-19 17:56:27 +08:00
" <CCBMFontConfiguration = " CC_FORMAT_PRINTF_SIZE_T " | Glphys:%d Kernings:%d | Image = %s> " ,
( size_t ) this ,
2013-06-15 14:03:30 +08:00
HASH_COUNT ( _fontDefDictionary ) ,
HASH_COUNT ( _kerningDictionary ) ,
_atlasName . c_str ( )
2013-12-11 17:15:27 +08:00
) ;
2012-03-20 15:04:53 +08:00
}
2012-03-22 09:46:07 +08:00
2012-03-20 15:04:53 +08:00
void CCBMFontConfiguration : : purgeKerningDictionary ( )
{
2013-06-20 14:13:12 +08:00
tKerningHashElement * current ;
2013-06-15 14:03:30 +08:00
while ( _kerningDictionary )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
current = _kerningDictionary ;
HASH_DEL ( _kerningDictionary , current ) ;
2012-04-19 14:35:52 +08:00
free ( current ) ;
}
2012-03-20 15:04:53 +08:00
}
2012-03-22 09:46:07 +08:00
2012-04-06 23:33:42 +08:00
void CCBMFontConfiguration : : purgeFontDefDictionary ( )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
tFontDefHashElement * current , * tmp ;
2012-04-06 23:33:42 +08:00
2013-06-15 14:03:30 +08:00
HASH_ITER ( hh , _fontDefDictionary , current , tmp ) {
HASH_DEL ( _fontDefDictionary , current ) ;
2012-04-19 14:35:52 +08:00
free ( current ) ;
}
2012-04-06 23:33:42 +08:00
}
2012-03-22 09:46:07 +08:00
2013-11-06 11:02:03 +08:00
std : : set < unsigned int > * CCBMFontConfiguration : : parseConfigFile ( const std : : string & controlFile )
2012-04-19 14:35:52 +08:00
{
2013-07-12 06:24:23 +08:00
std : : string fullpath = FileUtils : : getInstance ( ) - > fullPathForFilename ( controlFile ) ;
2013-12-28 02:29:59 +08:00
Data data = FileUtils : : getInstance ( ) - > getDataFromFile ( fullpath ) ;
CCASSERT ( ( ! data . isNull ( ) & & data . getSize ( ) > 0 ) , " CCBMFontConfiguration::parseConfigFile | Open file error. " ) ;
if ( memcmp ( " BMF " , data . getBytes ( ) , 3 ) = = 0 ) {
std : : set < unsigned int > * ret = parseBinaryConfigFile ( data . getBytes ( ) , data . getSize ( ) , controlFile ) ;
return ret ;
}
2013-12-29 03:00:07 +08:00
std : : string contents ( ( const char * ) data . getBytes ( ) , data . getSize ( ) ) ;
2012-11-15 17:16:51 +08:00
2013-12-18 14:58:17 +08:00
std : : set < unsigned int > * validCharsString = new std : : set < unsigned int > ( ) ;
2012-04-19 14:35:52 +08:00
2013-12-18 14:58:17 +08:00
if ( contents . empty ( ) )
2012-04-19 14:35:52 +08:00
{
2013-11-06 11:02:03 +08:00
CCLOG ( " cocos2d: Error parsing FNTfile %s " , controlFile . c_str ( ) ) ;
2013-12-18 17:47:20 +08:00
return nullptr ;
2012-04-19 14:35:52 +08:00
}
// parse spacing / padding
std : : string line ;
2013-12-18 14:58:17 +08:00
std : : string strLeft ( contents ) ;
2012-04-19 14:35:52 +08:00
while ( strLeft . length ( ) > 0 )
{
2013-11-05 08:31:36 +08:00
size_t pos = strLeft . find ( ' \n ' ) ;
2012-04-19 14:35:52 +08:00
2013-11-13 11:22:34 +08:00
if ( pos ! = std : : string : : npos )
2012-04-19 14:35:52 +08:00
{
// the data is more than a line.get one line
line = strLeft . substr ( 0 , pos ) ;
strLeft = strLeft . substr ( pos + 1 ) ;
}
else
{
// get the left data
line = strLeft ;
strLeft . erase ( ) ;
}
if ( line . substr ( 0 , strlen ( " info face " ) ) = = " info face " )
{
// XXX: info parsing is incomplete
// Not needed for the Hiero editors, but needed for the AngelCode editor
// [self parseInfoArguments:line];
this - > parseInfoArguments ( line ) ;
}
// Check to see if the start of the line is something we are interested in
else if ( line . substr ( 0 , strlen ( " common lineHeight " ) ) = = " common lineHeight " )
{
this - > parseCommonArguments ( line ) ;
}
else if ( line . substr ( 0 , strlen ( " page id " ) ) = = " page id " )
{
this - > parseImageFileName ( line , controlFile ) ;
}
else if ( line . substr ( 0 , strlen ( " chars c " ) ) = = " chars c " )
{
// Ignore this line
}
else if ( line . substr ( 0 , strlen ( " char " ) ) = = " char " )
{
// Parse the current line and create a new CharDef
2013-06-20 14:13:12 +08:00
tFontDefHashElement * element = ( tFontDefHashElement * ) malloc ( sizeof ( * element ) ) ;
2012-04-19 14:35:52 +08:00
this - > parseCharacterDefinition ( line , & element - > fontDef ) ;
element - > key = element - > fontDef . charID ;
2013-06-15 14:03:30 +08:00
HASH_ADD_INT ( _fontDefDictionary , key , element ) ;
2012-11-15 17:16:51 +08:00
validCharsString - > insert ( element - > fontDef . charID ) ;
2012-04-19 14:35:52 +08:00
}
2012-06-08 15:29:47 +08:00
// else if(line.substr(0,strlen("kernings count")) == "kernings count")
// {
// this->parseKerningCapacity(line);
// }
2012-04-19 14:35:52 +08:00
else if ( line . substr ( 0 , strlen ( " kerning first " ) ) = = " kerning first " )
{
this - > parseKerningEntry ( line ) ;
}
}
2012-06-08 15:29:47 +08:00
2012-11-15 17:16:51 +08:00
return validCharsString ;
2012-03-20 15:04:53 +08:00
}
2012-03-22 09:46:07 +08:00
2013-12-28 02:29:59 +08:00
std : : set < unsigned int > * CCBMFontConfiguration : : parseBinaryConfigFile ( unsigned char * pData , unsigned long size , const std : : string & controlFile )
{
/* based on http://www.angelcode.com/products/bmfont/doc/file_format.html file format */
set < unsigned int > * validCharsString = new set < unsigned int > ( ) ;
unsigned long remains = size ;
unsigned char version = pData [ 3 ] ;
CCASSERT ( version = = 3 , " Only version 3 is supported " ) ;
pData + = 4 ; remains - = 4 ;
while ( remains > 0 )
{
unsigned char blockId = pData [ 0 ] ; pData + = 1 ; remains - = 1 ;
uint32_t blockSize = 0 ; memcpy ( & blockSize , pData , 4 ) ;
pData + = 4 ; remains - = 4 ;
if ( blockId = = 1 )
{
/*
fontSize 2 int 0
bitField 1 bits 2 bit 0 : smooth , bit 1 : unicode , bit 2 : italic , bit 3 : bold , bit 4 : fixedHeigth , bits 5 - 7 : reserved
charSet 1 uint 3
stretchH 2 uint 4
aa 1 uint 6
paddingUp 1 uint 7
paddingRight 1 uint 8
paddingDown 1 uint 9
paddingLeft 1 uint 10
spacingHoriz 1 uint 11
spacingVert 1 uint 12
outline 1 uint 13 added with version 2
fontName n + 1 string 14 null terminated string with length n
*/
_padding . top = ( unsigned char ) pData [ 7 ] ;
_padding . right = ( unsigned char ) pData [ 8 ] ;
_padding . bottom = ( unsigned char ) pData [ 9 ] ;
_padding . left = ( unsigned char ) pData [ 10 ] ;
}
else if ( blockId = = 2 )
{
/*
lineHeight 2 uint 0
base 2 uint 2
scaleW 2 uint 4
scaleH 2 uint 6
pages 2 uint 8
bitField 1 bits 10 bits 0 - 6 : reserved , bit 7 : packed
alphaChnl 1 uint 11
redChnl 1 uint 12
greenChnl 1 uint 13
blueChnl 1 uint 14
*/
uint16_t lineHeight = 0 ; memcpy ( & lineHeight , pData , 2 ) ;
_commonHeight = lineHeight ;
uint16_t scaleW = 0 ; memcpy ( & scaleW , pData + 4 , 2 ) ;
uint16_t scaleH = 0 ; memcpy ( & scaleH , pData + 6 , 2 ) ;
CCASSERT ( scaleW < = Configuration : : getInstance ( ) - > getMaxTextureSize ( ) & & scaleH < = Configuration : : getInstance ( ) - > getMaxTextureSize ( ) , " CCLabelBMFont: page can't be larger than supported " ) ;
uint16_t pages = 0 ; memcpy ( & pages , pData + 8 , 2 ) ;
CCASSERT ( pages = = 1 , " CCBitfontAtlas: only supports 1 page " ) ;
}
else if ( blockId = = 3 )
{
/*
pageNames p * ( n + 1 ) strings 0 p null terminated strings , each with length n
*/
const char * value = ( const char * ) pData ;
size_t len = strlen ( value ) ;
CCASSERT ( len < blockSize , " Block size should be less then string " ) ;
_atlasName = FileUtils : : getInstance ( ) - > fullPathFromRelativeFile ( value , controlFile ) ;
}
else if ( blockId = = 4 )
{
/*
id 4 uint 0 + c * 20 These fields are repeated until all characters have been described
x 2 uint 4 + c * 20
y 2 uint 6 + c * 20
width 2 uint 8 + c * 20
height 2 uint 10 + c * 20
xoffset 2 int 12 + c * 20
yoffset 2 int 14 + c * 20
xadvance 2 int 16 + c * 20
page 1 uint 18 + c * 20
chnl 1 uint 19 + c * 20
*/
unsigned long count = blockSize / 20 ;
for ( unsigned long i = 0 ; i < count ; i + + )
{
tFontDefHashElement * element = ( tFontDefHashElement * ) malloc ( sizeof ( * element ) ) ;
uint32_t charId = 0 ; memcpy ( & charId , pData + ( i * 20 ) , 4 ) ;
element - > fontDef . charID = charId ;
uint16_t charX = 0 ; memcpy ( & charX , pData + ( i * 20 ) + 4 , 2 ) ;
element - > fontDef . rect . origin . x = charX ;
uint16_t charY = 0 ; memcpy ( & charY , pData + ( i * 20 ) + 6 , 2 ) ;
element - > fontDef . rect . origin . y = charY ;
uint16_t charWidth = 0 ; memcpy ( & charWidth , pData + ( i * 20 ) + 8 , 2 ) ;
element - > fontDef . rect . size . width = charWidth ;
uint16_t charHeight = 0 ; memcpy ( & charHeight , pData + ( i * 20 ) + 10 , 2 ) ;
element - > fontDef . rect . size . height = charHeight ;
int16_t xoffset = 0 ; memcpy ( & xoffset , pData + ( i * 20 ) + 12 , 2 ) ;
element - > fontDef . xOffset = xoffset ;
int16_t yoffset = 0 ; memcpy ( & yoffset , pData + ( i * 20 ) + 14 , 2 ) ;
element - > fontDef . yOffset = yoffset ;
int16_t xadvance = 0 ; memcpy ( & xadvance , pData + ( i * 20 ) + 16 , 2 ) ;
element - > fontDef . xAdvance = xadvance ;
element - > key = element - > fontDef . charID ;
HASH_ADD_INT ( _fontDefDictionary , key , element ) ;
validCharsString - > insert ( element - > fontDef . charID ) ;
}
}
else if ( blockId = = 5 ) {
/*
first 4 uint 0 + c * 10 These fields are repeated until all kerning pairs have been described
second 4 uint 4 + c * 10
amount 2 int 8 + c * 10
*/
unsigned long count = blockSize / 20 ;
for ( unsigned long i = 0 ; i < count ; i + + )
{
uint32_t first = 0 ; memcpy ( & first , pData + ( i * 10 ) , 4 ) ;
uint32_t second = 0 ; memcpy ( & second , pData + ( i * 10 ) + 4 , 4 ) ;
int16_t amount = 0 ; memcpy ( & amount , pData + ( i * 10 ) + 8 , 2 ) ;
tKerningHashElement * element = ( tKerningHashElement * ) calloc ( sizeof ( * element ) , 1 ) ;
element - > amount = amount ;
element - > key = ( first < < 16 ) | ( second & 0xffff ) ;
HASH_ADD_INT ( _kerningDictionary , key , element ) ;
}
}
pData + = blockSize ; remains - = blockSize ;
}
return validCharsString ;
}
2013-11-06 11:02:03 +08:00
void CCBMFontConfiguration : : parseImageFileName ( std : : string line , const std : : string & fntFile )
2012-03-20 15:04:53 +08:00
{
2012-04-19 14:35:52 +08:00
//////////////////////////////////////////////////////////////////////////
// line to parse:
// page id=0 file="bitmapFontTest.png"
//////////////////////////////////////////////////////////////////////////
// page ID. Sanity check
2013-12-05 17:19:01 +08:00
auto index = line . find ( ' = ' ) + 1 ;
auto index2 = line . find ( ' ' , index ) ;
2012-04-19 14:35:52 +08:00
std : : string value = line . substr ( index , index2 - index ) ;
2013-07-20 13:01:27 +08:00
CCASSERT ( atoi ( value . c_str ( ) ) = = 0 , " LabelBMFont file could not be found " ) ;
2012-04-19 14:35:52 +08:00
// file
index = line . find ( ' " ' ) + 1 ;
index2 = line . find ( ' " ' , index ) ;
value = line . substr ( index , index2 - index ) ;
2013-07-12 06:24:23 +08:00
_atlasName = FileUtils : : getInstance ( ) - > fullPathFromRelativeFile ( value . c_str ( ) , fntFile ) ;
2012-03-20 15:04:53 +08:00
}
2012-03-22 09:46:07 +08:00
2012-03-20 15:04:53 +08:00
void CCBMFontConfiguration : : parseInfoArguments ( std : : string line )
{
2012-04-19 14:35:52 +08:00
//////////////////////////////////////////////////////////////////////////
// possible lines to parse:
// info face="Script" size=32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=1,4,3,2 spacing=0,0 outline=0
// info face="Cracked" size=36 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1
//////////////////////////////////////////////////////////////////////////
// padding
2013-12-05 17:19:01 +08:00
auto index = line . find ( " padding= " ) ;
auto index2 = line . find ( ' ' , index ) ;
2012-04-19 14:35:52 +08:00
std : : string value = line . substr ( index , index2 - index ) ;
2013-06-15 14:03:30 +08:00
sscanf ( value . c_str ( ) , " padding=%d,%d,%d,%d " , & _padding . top , & _padding . right , & _padding . bottom , & _padding . left ) ;
CCLOG ( " cocos2d: padding: %d,%d,%d,%d " , _padding . left , _padding . top , _padding . right , _padding . bottom ) ;
2012-03-20 15:04:53 +08:00
}
2012-03-22 09:46:07 +08:00
2012-03-20 15:04:53 +08:00
void CCBMFontConfiguration : : parseCommonArguments ( std : : string line )
{
2012-04-19 14:35:52 +08:00
//////////////////////////////////////////////////////////////////////////
// line to parse:
// common lineHeight=104 base=26 scaleW=1024 scaleH=512 pages=1 packed=0
//////////////////////////////////////////////////////////////////////////
// Height
2013-12-05 17:19:01 +08:00
auto index = line . find ( " lineHeight= " ) ;
auto index2 = line . find ( ' ' , index ) ;
2012-04-19 14:35:52 +08:00
std : : string value = line . substr ( index , index2 - index ) ;
2013-06-15 14:03:30 +08:00
sscanf ( value . c_str ( ) , " lineHeight=%d " , & _commonHeight ) ;
2012-04-19 14:35:52 +08:00
// scaleW. sanity check
index = line . find ( " scaleW= " ) + strlen ( " scaleW= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
2013-07-20 13:01:27 +08:00
CCASSERT ( atoi ( value . c_str ( ) ) < = Configuration : : getInstance ( ) - > getMaxTextureSize ( ) , " CCLabelBMFont: page can't be larger than supported " ) ;
2012-04-19 14:35:52 +08:00
// scaleH. sanity check
index = line . find ( " scaleH= " ) + strlen ( " scaleH= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
2013-07-20 13:01:27 +08:00
CCASSERT ( atoi ( value . c_str ( ) ) < = Configuration : : getInstance ( ) - > getMaxTextureSize ( ) , " CCLabelBMFont: page can't be larger than supported " ) ;
2012-04-19 14:35:52 +08:00
// pages. sanity check
index = line . find ( " pages= " ) + strlen ( " pages= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
2013-07-20 13:01:27 +08:00
CCASSERT ( atoi ( value . c_str ( ) ) = = 1 , " CCBitfontAtlas: only supports 1 page " ) ;
2012-04-19 14:35:52 +08:00
// packed (ignore) What does this mean ??
2012-03-20 15:04:53 +08:00
}
2012-03-22 09:46:07 +08:00
2012-03-20 15:04:53 +08:00
void CCBMFontConfiguration : : parseCharacterDefinition ( std : : string line , ccBMFontDef * characterDefinition )
2012-04-19 14:35:52 +08:00
{
//////////////////////////////////////////////////////////////////////////
// line to parse:
// char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=44 xadvance=14 page=0 chnl=0
//////////////////////////////////////////////////////////////////////////
// Character ID
2013-12-05 17:19:01 +08:00
auto index = line . find ( " id= " ) ;
auto index2 = line . find ( ' ' , index ) ;
2012-04-19 14:35:52 +08:00
std : : string value = line . substr ( index , index2 - index ) ;
sscanf ( value . c_str ( ) , " id=%u " , & characterDefinition - > charID ) ;
// Character x
index = line . find ( " x= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
sscanf ( value . c_str ( ) , " x=%f " , & characterDefinition - > rect . origin . x ) ;
// Character y
index = line . find ( " y= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
sscanf ( value . c_str ( ) , " y=%f " , & characterDefinition - > rect . origin . y ) ;
// Character width
index = line . find ( " width= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
sscanf ( value . c_str ( ) , " width=%f " , & characterDefinition - > rect . size . width ) ;
// Character height
index = line . find ( " height= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
sscanf ( value . c_str ( ) , " height=%f " , & characterDefinition - > rect . size . height ) ;
// Character xoffset
index = line . find ( " xoffset= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
2012-08-16 18:09:01 +08:00
sscanf ( value . c_str ( ) , " xoffset=%hd " , & characterDefinition - > xOffset ) ;
2012-04-19 14:35:52 +08:00
// Character yoffset
index = line . find ( " yoffset= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
2012-08-16 18:09:01 +08:00
sscanf ( value . c_str ( ) , " yoffset=%hd " , & characterDefinition - > yOffset ) ;
2012-04-19 14:35:52 +08:00
// Character xadvance
index = line . find ( " xadvance= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
2012-08-16 18:09:01 +08:00
sscanf ( value . c_str ( ) , " xadvance=%hd " , & characterDefinition - > xAdvance ) ;
2012-03-20 15:04:53 +08:00
}
2012-03-22 09:46:07 +08:00
2012-03-20 15:04:53 +08:00
void CCBMFontConfiguration : : parseKerningEntry ( std : : string line )
2012-04-19 14:35:52 +08:00
{
//////////////////////////////////////////////////////////////////////////
// line to parse:
// kerning first=121 second=44 amount=-7
//////////////////////////////////////////////////////////////////////////
// first
int first ;
2013-12-05 17:19:01 +08:00
auto index = line . find ( " first= " ) ;
auto index2 = line . find ( ' ' , index ) ;
2012-04-19 14:35:52 +08:00
std : : string value = line . substr ( index , index2 - index ) ;
sscanf ( value . c_str ( ) , " first=%d " , & first ) ;
// second
int second ;
index = line . find ( " second= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
sscanf ( value . c_str ( ) , " second=%d " , & second ) ;
// amount
int amount ;
index = line . find ( " amount= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
sscanf ( value . c_str ( ) , " amount=%d " , & amount ) ;
2013-06-20 14:13:12 +08:00
tKerningHashElement * element = ( tKerningHashElement * ) calloc ( sizeof ( * element ) , 1 ) ;
2012-04-19 14:35:52 +08:00
element - > amount = amount ;
element - > key = ( first < < 16 ) | ( second & 0xffff ) ;
2013-06-15 14:03:30 +08:00
HASH_ADD_INT ( _kerningDictionary , key , element ) ;
2012-03-20 15:04:53 +08:00
}
//
//CCLabelBMFont
//
//LabelBMFont - Purge Cache
2013-06-20 14:13:12 +08:00
void LabelBMFont : : purgeCachedData ( )
2012-03-20 15:04:53 +08:00
{
2012-04-19 14:35:52 +08:00
FNTConfigRemoveCache ( ) ;
2012-03-20 15:04:53 +08:00
}
2010-08-12 17:39:25 +08:00
2013-06-20 14:13:12 +08:00
LabelBMFont * LabelBMFont : : create ( )
2012-06-15 15:10:40 +08:00
{
2013-06-20 14:13:12 +08:00
LabelBMFont * pRet = new LabelBMFont ( ) ;
2012-06-15 15:10:40 +08:00
if ( pRet & & pRet - > init ( ) )
{
pRet - > autorelease ( ) ;
return pRet ;
}
CC_SAFE_DELETE ( pRet ) ;
2013-12-18 17:47:20 +08:00
return nullptr ;
2012-06-15 15:10:40 +08:00
}
2012-06-14 18:32:44 +08:00
2013-11-06 11:02:03 +08:00
LabelBMFont * LabelBMFont : : create ( const std : : string & str , const std : : string & fntFile , float width , TextHAlignment alignment )
2012-11-02 10:06:48 +08:00
{
2013-07-12 14:47:36 +08:00
return LabelBMFont : : create ( str , fntFile , width , alignment , Point : : ZERO ) ;
2012-11-02 10:06:48 +08:00
}
2013-11-06 11:02:03 +08:00
LabelBMFont * LabelBMFont : : create ( const std : : string & str , const std : : string & fntFile , float width )
2012-11-02 10:06:48 +08:00
{
2013-07-27 07:04:21 +08:00
return LabelBMFont : : create ( str , fntFile , width , TextHAlignment : : LEFT , Point : : ZERO ) ;
2012-11-02 10:06:48 +08:00
}
2013-11-06 11:02:03 +08:00
LabelBMFont * LabelBMFont : : create ( const std : : string & str , const std : : string & fntFile )
2012-11-02 10:06:48 +08:00
{
2013-07-27 07:04:21 +08:00
return LabelBMFont : : create ( str , fntFile , kLabelAutomaticWidth , TextHAlignment : : LEFT , Point : : ZERO ) ;
2012-11-02 10:06:48 +08:00
}
2012-03-22 09:46:07 +08:00
//LabelBMFont - Creation & Init
2013-11-06 11:02:03 +08:00
LabelBMFont * LabelBMFont : : create ( const std : : string & str , const std : : string & fntFile , float width /* = kLabelAutomaticWidth*/ , TextHAlignment alignment /* = TextHAlignment::LEFT*/ , Point imageOffset /* = Point::ZERO*/ )
2012-03-22 09:46:07 +08:00
{
2013-12-18 17:47:20 +08:00
LabelBMFont * ret = new LabelBMFont ( ) ;
if ( ret & & ret - > initWithString ( str , fntFile , width , alignment , imageOffset ) )
2012-04-19 14:35:52 +08:00
{
2013-12-18 17:47:20 +08:00
ret - > autorelease ( ) ;
return ret ;
2012-04-19 14:35:52 +08:00
}
2013-12-18 17:47:20 +08:00
CC_SAFE_DELETE ( ret ) ;
return nullptr ;
2012-03-22 09:46:07 +08:00
}
2013-06-20 14:13:12 +08:00
bool LabelBMFont : : init ( )
2012-06-12 14:33:53 +08:00
{
2013-11-06 11:02:03 +08:00
return initWithString ( " " , " " , kLabelAutomaticWidth , TextHAlignment : : LEFT , Point : : ZERO ) ;
2012-06-12 14:33:53 +08:00
}
2013-11-06 11:02:03 +08:00
bool LabelBMFont : : initWithString ( const std : : string & theString , const std : : string & fntFile , float width /* = kLabelAutomaticWidth*/ , TextHAlignment alignment /* = TextHAlignment::LEFT*/ , Point imageOffset /* = Point::ZERO*/ )
2012-03-22 09:46:07 +08:00
{
2013-07-20 13:01:27 +08:00
CCASSERT ( ! _configuration , " re-init is no longer supported " ) ;
2013-11-06 11:02:03 +08:00
2013-12-18 17:47:20 +08:00
Texture2D * texture = nullptr ;
2012-06-08 15:29:47 +08:00
2013-11-06 11:02:03 +08:00
if ( fntFile . size ( ) > 0 )
2012-06-08 15:29:47 +08:00
{
CCBMFontConfiguration * newConf = FNTConfigLoadFile ( fntFile ) ;
2012-11-15 17:16:51 +08:00
if ( ! newConf )
{
2013-11-06 11:02:03 +08:00
CCLOG ( " cocos2d: WARNING. LabelBMFont: Impossible to create font. Please check file: '%s' " , fntFile . c_str ( ) ) ;
2012-11-15 17:16:51 +08:00
release ( ) ;
return false ;
}
2012-06-08 15:29:47 +08:00
newConf - > retain ( ) ;
2013-06-15 14:03:30 +08:00
CC_SAFE_RELEASE ( _configuration ) ;
_configuration = newConf ;
2012-06-08 15:29:47 +08:00
2013-06-15 14:03:30 +08:00
_fntFile = fntFile ;
2012-06-08 15:29:47 +08:00
2013-11-07 19:11:09 +08:00
texture = Director : : getInstance ( ) - > getTextureCache ( ) - > addImage ( _configuration - > getAtlasName ( ) ) ;
2012-06-08 15:29:47 +08:00
}
else
{
2013-06-20 14:13:12 +08:00
texture = new Texture2D ( ) ;
2012-06-08 15:29:47 +08:00
texture - > autorelease ( ) ;
}
2012-04-19 14:35:52 +08:00
2013-12-06 16:32:06 +08:00
if ( SpriteBatchNode : : initWithTexture ( texture , static_cast < int > ( theString . size ( ) ) ) )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
_width = width ;
_alignment = alignment ;
2013-02-28 10:37:47 +08:00
2013-06-15 14:03:30 +08:00
_displayedOpacity = _realOpacity = 255 ;
2013-07-08 18:11:32 +08:00
_displayedColor = _realColor = Color3B : : WHITE ;
2013-06-15 14:03:30 +08:00
_cascadeOpacityEnabled = true ;
_cascadeColorEnabled = true ;
2013-02-28 10:37:47 +08:00
2013-07-12 14:47:36 +08:00
_contentSize = Size : : ZERO ;
2013-02-28 10:37:47 +08:00
2013-06-15 14:03:30 +08:00
_isOpacityModifyRGB = _textureAtlas - > getTexture ( ) - > hasPremultipliedAlpha ( ) ;
2013-07-12 14:11:55 +08:00
_anchorPoint = Point ( 0.5f , 0.5f ) ;
2012-11-15 17:16:51 +08:00
2013-06-15 14:03:30 +08:00
_imageOffset = imageOffset ;
2013-02-28 10:37:47 +08:00
2013-11-14 07:55:36 +08:00
_reusedChar = Sprite : : createWithTexture ( _textureAtlas - > getTexture ( ) , Rect ( 0 , 0 , 0 , 0 ) ) ;
_reusedChar - > retain ( ) ;
2013-06-15 14:03:30 +08:00
_reusedChar - > setBatchNode ( this ) ;
2012-11-15 17:16:51 +08:00
2013-02-28 10:37:47 +08:00
this - > setString ( theString , true ) ;
2012-11-15 17:16:51 +08:00
2012-04-19 14:35:52 +08:00
return true ;
}
return false ;
2012-03-20 15:04:53 +08:00
}
2012-03-22 09:46:07 +08:00
2013-06-20 14:13:12 +08:00
LabelBMFont : : LabelBMFont ( )
2013-12-18 17:47:20 +08:00
: _string ( nullptr )
, _initialString ( nullptr )
2013-07-27 07:04:21 +08:00
, _alignment ( TextHAlignment : : CENTER )
2013-06-15 14:03:30 +08:00
, _width ( - 1.0f )
2013-12-18 17:47:20 +08:00
, _configuration ( nullptr )
2013-06-15 14:03:30 +08:00
, _lineBreakWithoutSpaces ( false )
2013-07-12 14:47:36 +08:00
, _imageOffset ( Point : : ZERO )
2013-12-18 17:47:20 +08:00
, _reusedChar ( nullptr )
2013-06-15 14:03:30 +08:00
, _isOpacityModifyRGB ( false )
2012-03-22 09:46:07 +08:00
{
}
2013-06-20 14:13:12 +08:00
LabelBMFont : : ~ LabelBMFont ( )
2012-03-20 15:04:53 +08:00
{
2013-06-15 14:03:30 +08:00
CC_SAFE_RELEASE ( _reusedChar ) ;
CC_SAFE_DELETE_ARRAY ( _string ) ;
CC_SAFE_DELETE_ARRAY ( _initialString ) ;
CC_SAFE_RELEASE ( _configuration ) ;
2012-03-20 15:04:53 +08:00
}
2010-08-12 17:39:25 +08:00
2012-03-20 15:04:53 +08:00
// LabelBMFont - Atlas generation
2013-06-20 14:13:12 +08:00
int LabelBMFont : : kerningAmountForFirst ( unsigned short first , unsigned short second )
2012-03-20 15:04:53 +08:00
{
2012-04-19 14:35:52 +08:00
int ret = 0 ;
unsigned int key = ( first < < 16 ) | ( second & 0xffff ) ;
2013-06-15 14:03:30 +08:00
if ( _configuration - > _kerningDictionary ) {
2013-12-18 17:47:20 +08:00
tKerningHashElement * element = nullptr ;
2013-06-15 14:03:30 +08:00
HASH_FIND_INT ( _configuration - > _kerningDictionary , & key , element ) ;
2012-04-19 14:35:52 +08:00
if ( element )
ret = element - > amount ;
}
return ret ;
2012-03-20 15:04:53 +08:00
}
2012-01-18 18:02:39 +08:00
2013-06-20 14:13:12 +08:00
void LabelBMFont : : createFontChars ( )
2012-03-20 15:04:53 +08:00
{
2012-04-19 14:35:52 +08:00
int nextFontPositionX = 0 ;
2012-03-20 15:04:53 +08:00
int nextFontPositionY = 0 ;
2013-02-27 09:38:30 +08:00
unsigned short prev = - 1 ;
2012-04-19 14:35:52 +08:00
int kerningAmount = 0 ;
2010-08-12 17:39:25 +08:00
2013-07-12 14:47:36 +08:00
Size tmpSize = Size : : ZERO ;
2010-12-24 17:07:31 +08:00
2012-03-20 15:04:53 +08:00
int longestLine = 0 ;
unsigned int totalHeight = 0 ;
2011-11-09 22:11:36 +08:00
2012-03-20 15:04:53 +08:00
unsigned int quantityOfLines = 1 ;
2013-06-15 14:03:30 +08:00
unsigned int stringLen = _string ? cc_wcslen ( _string ) : 0 ;
2012-04-19 14:35:52 +08:00
if ( stringLen = = 0 )
{
return ;
}
2012-03-20 15:04:53 +08:00
2013-06-15 14:03:30 +08:00
set < unsigned int > * charSet = _configuration - > getCharacterSet ( ) ;
2012-11-21 10:06:03 +08:00
2012-03-20 15:04:53 +08:00
for ( unsigned int i = 0 ; i < stringLen - 1 ; + + i )
{
2013-06-15 14:03:30 +08:00
unsigned short c = _string [ i ] ;
2012-03-20 15:04:53 +08:00
if ( c = = ' \n ' )
{
quantityOfLines + + ;
2012-01-18 18:02:39 +08:00
}
2012-03-20 15:04:53 +08:00
}
2013-06-15 14:03:30 +08:00
totalHeight = _configuration - > _commonHeight * quantityOfLines ;
nextFontPositionY = 0 - ( _configuration - > _commonHeight - _configuration - > _commonHeight * quantityOfLines ) ;
2012-11-15 17:16:51 +08:00
2013-06-20 14:13:12 +08:00
Rect rect ;
2012-11-15 17:16:51 +08:00
ccBMFontDef fontDef ;
2012-01-18 18:02:39 +08:00
2012-04-19 14:35:52 +08:00
for ( unsigned int i = 0 ; i < stringLen ; i + + )
{
2013-06-15 14:03:30 +08:00
unsigned short c = _string [ i ] ;
2011-11-09 22:11:36 +08:00
2012-03-20 15:04:53 +08:00
if ( c = = ' \n ' )
2011-11-09 22:11:36 +08:00
{
2012-03-20 15:04:53 +08:00
nextFontPositionX = 0 ;
2013-06-15 14:03:30 +08:00
nextFontPositionY - = _configuration - > _commonHeight ;
2012-03-20 15:04:53 +08:00
continue ;
2011-11-09 22:11:36 +08:00
}
2012-11-15 17:16:51 +08:00
if ( charSet - > find ( c ) = = charSet - > end ( ) )
{
2013-06-20 14:13:12 +08:00
CCLOGWARN ( " cocos2d::LabelBMFont: Attempted to use character not defined in this bitmap: %d " , c ) ;
2012-11-15 17:16:51 +08:00
continue ;
}
2011-11-09 22:11:36 +08:00
2013-02-27 09:38:30 +08:00
kerningAmount = this - > kerningAmountForFirst ( prev , c ) ;
2013-12-18 17:47:20 +08:00
tFontDefHashElement * element = nullptr ;
2012-04-06 23:33:42 +08:00
2012-04-19 14:35:52 +08:00
// unichar is a short, and an int is needed on HASH_FIND_INT
unsigned int key = c ;
2013-06-15 14:03:30 +08:00
HASH_FIND_INT ( _configuration - > _fontDefDictionary , & key , element ) ;
2012-11-15 17:16:51 +08:00
if ( ! element )
{
2013-06-20 14:13:12 +08:00
CCLOGWARN ( " cocos2d::LabelBMFont: characer not found %d " , c ) ;
2012-11-15 17:16:51 +08:00
continue ;
}
2012-04-06 23:33:42 +08:00
2012-11-15 17:16:51 +08:00
fontDef = element - > fontDef ;
2012-04-06 23:33:42 +08:00
2012-11-15 17:16:51 +08:00
rect = fontDef . rect ;
2012-04-19 14:35:52 +08:00
rect = CC_RECT_PIXELS_TO_POINTS ( rect ) ;
2012-04-06 23:33:42 +08:00
2013-06-15 14:03:30 +08:00
rect . origin . x + = _imageOffset . x ;
rect . origin . y + = _imageOffset . y ;
2012-01-18 18:43:41 +08:00
2013-06-20 14:13:12 +08:00
Sprite * fontChar ;
2012-03-20 15:04:53 +08:00
2012-11-15 17:16:51 +08:00
bool hasSprite = true ;
2013-07-09 05:38:14 +08:00
fontChar = static_cast < Sprite * > ( this - > getChildByTag ( i ) ) ;
2013-02-27 09:38:30 +08:00
if ( fontChar )
2012-04-19 14:35:52 +08:00
{
2013-02-27 09:38:30 +08:00
// Reusing previous Sprite
fontChar - > setVisible ( true ) ;
}
else
2012-04-19 14:35:52 +08:00
{
2013-02-27 09:38:30 +08:00
// New Sprite ? Set correct color, opacity, etc...
2012-11-15 17:16:51 +08:00
if ( 0 )
{
/* WIP: Doesn't support many features yet.
But this code is super fast . It doesn ' t create any sprite .
Ideal for big labels .
*/
2013-06-15 14:03:30 +08:00
fontChar = _reusedChar ;
2013-12-18 17:47:20 +08:00
fontChar - > setBatchNode ( nullptr ) ;
2012-11-15 17:16:51 +08:00
hasSprite = false ;
}
else
{
2013-11-14 07:55:36 +08:00
fontChar = Sprite : : createWithTexture ( _textureAtlas - > getTexture ( ) , rect ) ;
2012-11-15 17:16:51 +08:00
addChild ( fontChar , i , i ) ;
}
2013-02-27 09:38:30 +08:00
// Apply label properties
2013-06-15 14:03:30 +08:00
fontChar - > setOpacityModifyRGB ( _isOpacityModifyRGB ) ;
2013-02-27 09:38:30 +08:00
// Color MUST be set before opacity, since opacity might change color if OpacityModifyRGB is on
2013-06-15 14:03:30 +08:00
fontChar - > updateDisplayedColor ( _displayedColor ) ;
fontChar - > updateDisplayedOpacity ( _displayedOpacity ) ;
2012-04-19 14:35:52 +08:00
}
2010-12-24 17:07:31 +08:00
2013-02-27 09:38:30 +08:00
// updating previous sprite
fontChar - > setTextureRect ( rect , false , rect . size ) ;
2010-12-24 17:07:31 +08:00
2012-06-08 15:29:47 +08:00
// See issue 1343. cast( signed short + unsigned integer ) == unsigned integer (sign is lost!)
2013-06-15 14:03:30 +08:00
int yOffset = _configuration - > _commonHeight - fontDef . yOffset ;
2013-07-12 14:11:55 +08:00
Point fontPos = Point ( ( float ) nextFontPositionX + fontDef . xOffset + fontDef . rect . size . width * 0.5f + kerningAmount ,
2012-04-19 14:35:52 +08:00
( float ) nextFontPositionY + yOffset - rect . size . height * 0.5f * CC_CONTENT_SCALE_FACTOR ( ) ) ;
fontChar - > setPosition ( CC_POINT_PIXELS_TO_POINTS ( fontPos ) ) ;
// update kerning
nextFontPositionX + = fontDef . xAdvance + kerningAmount ;
2013-02-27 09:38:30 +08:00
prev = c ;
2010-08-12 17:39:25 +08:00
2012-03-20 15:04:53 +08:00
if ( longestLine < nextFontPositionX )
{
longestLine = nextFontPositionX ;
}
2012-11-15 17:16:51 +08:00
if ( ! hasSprite )
{
updateQuadFromSprite ( fontChar , i ) ;
}
2012-04-19 14:35:52 +08:00
}
2010-12-28 15:05:55 +08:00
2012-11-15 17:16:51 +08:00
// If the last character processed has an xAdvance which is less that the width of the characters image, then we need
// to adjust the width of the string to take this into account, or the character will overlap the end of the bounding
// box
if ( fontDef . xAdvance < fontDef . rect . size . width )
{
tmpSize . width = longestLine + fontDef . rect . size . width - fontDef . xAdvance ;
}
else
{
tmpSize . width = longestLine ;
}
tmpSize . height = totalHeight ;
2012-03-20 15:04:53 +08:00
2012-04-19 14:35:52 +08:00
this - > setContentSize ( CC_SIZE_PIXELS_TO_POINTS ( tmpSize ) ) ;
2012-03-20 15:04:53 +08:00
}
2013-06-20 14:13:12 +08:00
//LabelBMFont - LabelProtocol protocol
2013-11-06 11:02:03 +08:00
void LabelBMFont : : setString ( const std : : string & newString )
2012-03-22 09:46:07 +08:00
{
2013-03-20 13:55:43 +08:00
this - > setString ( newString , true ) ;
2012-03-22 09:46:07 +08:00
}
2013-11-06 11:02:03 +08:00
void LabelBMFont : : setString ( const std : : string & newString , bool needUpdateLabel )
2013-03-20 13:55:43 +08:00
{
if ( needUpdateLabel ) {
2013-06-15 14:03:30 +08:00
_initialStringUTF8 = newString ;
2013-03-20 13:55:43 +08:00
}
2013-11-06 11:02:03 +08:00
unsigned short * utf16String = cc_utf8_to_utf16 ( newString . c_str ( ) ) ;
2013-03-20 13:55:43 +08:00
setString ( utf16String , needUpdateLabel ) ;
CC_SAFE_DELETE_ARRAY ( utf16String ) ;
}
2013-06-20 14:13:12 +08:00
void LabelBMFont : : setString ( unsigned short * newString , bool needUpdateLabel )
2013-03-20 13:55:43 +08:00
{
if ( ! needUpdateLabel )
2013-03-01 18:15:20 +08:00
{
2013-06-15 14:03:30 +08:00
unsigned short * tmp = _string ;
_string = copyUTF16StringN ( newString ) ;
2013-03-20 13:55:43 +08:00
CC_SAFE_DELETE_ARRAY ( tmp ) ;
2013-03-01 18:15:20 +08:00
}
else
{
2013-06-15 14:03:30 +08:00
unsigned short * tmp = _initialString ;
_initialString = copyUTF16StringN ( newString ) ;
2013-03-20 13:55:43 +08:00
CC_SAFE_DELETE_ARRAY ( tmp ) ;
2013-03-01 18:15:20 +08:00
}
2013-12-19 10:33:04 +08:00
for ( const auto & child : _children )
2013-11-28 16:02:03 +08:00
child - > setVisible ( false ) ;
2012-04-19 14:35:52 +08:00
this - > createFontChars ( ) ;
2013-03-20 13:55:43 +08:00
if ( needUpdateLabel ) {
2012-04-19 14:35:52 +08:00
updateLabel ( ) ;
2013-03-20 13:55:43 +08:00
}
2012-03-20 15:04:53 +08:00
}
2013-11-08 04:42:16 +08:00
const std : : string & LabelBMFont : : getString ( ) const
2012-03-20 15:04:53 +08:00
{
2013-11-08 04:42:16 +08:00
return _initialStringUTF8 ;
2012-03-20 15:04:53 +08:00
}
2013-06-20 14:13:12 +08:00
void LabelBMFont : : setCString ( const char * label )
2012-03-20 15:04:53 +08:00
{
setString ( label ) ;
}
2013-02-27 09:38:30 +08:00
/** Override synthesized setOpacity to recurse items */
2013-06-20 14:13:12 +08:00
void LabelBMFont : : setOpacityModifyRGB ( bool var )
2012-03-20 15:04:53 +08:00
{
2013-06-15 14:03:30 +08:00
_isOpacityModifyRGB = var ;
2013-12-19 10:33:04 +08:00
for ( const auto & child : _children ) {
2013-12-19 17:05:59 +08:00
child - > setOpacityModifyRGB ( _isOpacityModifyRGB ) ;
2013-12-19 10:33:04 +08:00
}
2012-03-20 15:04:53 +08:00
}
2013-07-04 08:22:15 +08:00
bool LabelBMFont : : isOpacityModifyRGB ( ) const
2012-03-20 15:04:53 +08:00
{
2013-06-15 14:03:30 +08:00
return _isOpacityModifyRGB ;
2012-03-20 15:04:53 +08:00
}
2010-08-12 17:39:25 +08:00
2012-03-20 15:04:53 +08:00
// LabelBMFont - AnchorPoint
2013-06-20 14:13:12 +08:00
void LabelBMFont : : setAnchorPoint ( const Point & point )
2012-03-20 15:04:53 +08:00
{
2013-06-15 14:03:30 +08:00
if ( ! point . equals ( _anchorPoint ) )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
SpriteBatchNode : : setAnchorPoint ( point ) ;
2012-04-19 14:35:52 +08:00
updateLabel ( ) ;
}
2012-03-22 09:46:07 +08:00
}
// LabelBMFont - Alignment
2013-06-20 14:13:12 +08:00
void LabelBMFont : : updateLabel ( )
2012-03-22 09:46:07 +08:00
{
2013-06-15 14:03:30 +08:00
this - > setString ( _initialString , false ) ;
2012-05-31 15:32:18 +08:00
2013-06-15 14:03:30 +08:00
if ( _width > 0 )
2012-04-19 14:35:52 +08:00
{
// Step 1: Make multiline
2013-06-15 14:03:30 +08:00
vector < unsigned short > str_whole = cc_utf16_vec_from_utf16_str ( _string ) ;
2013-11-28 16:02:03 +08:00
size_t stringLength = str_whole . size ( ) ;
2012-04-19 14:35:52 +08:00
vector < unsigned short > multiline_string ;
2012-04-25 18:17:04 +08:00
multiline_string . reserve ( stringLength ) ;
2012-04-19 14:35:52 +08:00
vector < unsigned short > last_word ;
2012-04-25 18:17:04 +08:00
last_word . reserve ( stringLength ) ;
2012-04-25 18:08:23 +08:00
2012-05-29 17:11:33 +08:00
unsigned int line = 1 , i = 0 ;
2012-04-19 14:35:52 +08:00
bool start_line = false , start_word = false ;
float startOfLine = - 1 , startOfWord = - 1 ;
int skip = 0 ;
2013-11-28 16:02:03 +08:00
auto children = getChildren ( ) ;
2013-12-05 10:35:10 +08:00
for ( int j = 0 ; j < children . size ( ) ; j + + )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
Sprite * characterSprite ;
2013-02-27 09:38:30 +08:00
unsigned int justSkipped = 0 ;
2013-07-09 05:38:14 +08:00
while ( ! ( characterSprite = static_cast < Sprite * > ( this - > getChildByTag ( j + skip + justSkipped ) ) ) )
2013-02-27 09:38:30 +08:00
{
justSkipped + + ;
}
skip + = justSkipped ;
2012-04-19 14:35:52 +08:00
2012-05-29 17:11:33 +08:00
if ( i > = stringLength )
2012-04-19 14:35:52 +08:00
break ;
unsigned short character = str_whole [ i ] ;
if ( ! start_word )
{
2012-04-25 18:17:04 +08:00
startOfWord = getLetterPosXLeft ( characterSprite ) ;
2012-04-19 14:35:52 +08:00
start_word = true ;
}
if ( ! start_line )
{
startOfLine = startOfWord ;
start_line = true ;
}
// Newline.
if ( character = = ' \n ' )
{
cc_utf8_trim_ws ( & last_word ) ;
2012-04-25 18:17:04 +08:00
last_word . push_back ( ' \n ' ) ;
multiline_string . insert ( multiline_string . end ( ) , last_word . begin ( ) , last_word . end ( ) ) ;
last_word . clear ( ) ;
start_word = false ;
start_line = false ;
startOfWord = - 1 ;
startOfLine = - 1 ;
2013-02-27 09:38:30 +08:00
i + = justSkipped ;
2012-04-25 18:17:04 +08:00
line + + ;
2012-04-19 14:35:52 +08:00
2012-05-29 17:11:33 +08:00
if ( i > = stringLength )
2012-04-19 14:35:52 +08:00
break ;
character = str_whole [ i ] ;
if ( ! startOfWord )
{
2012-04-25 18:17:04 +08:00
startOfWord = getLetterPosXLeft ( characterSprite ) ;
2012-04-19 14:35:52 +08:00
start_word = true ;
}
if ( ! startOfLine )
{
startOfLine = startOfWord ;
start_line = true ;
}
2013-12-23 18:23:39 +08:00
+ + i ;
continue ;
2012-04-19 14:35:52 +08:00
}
// Whitespace.
if ( isspace_unicode ( character ) )
{
last_word . push_back ( character ) ;
multiline_string . insert ( multiline_string . end ( ) , last_word . begin ( ) , last_word . end ( ) ) ;
last_word . clear ( ) ;
start_word = false ;
startOfWord = - 1 ;
i + + ;
continue ;
}
// Out of bounds.
2013-06-15 14:03:30 +08:00
if ( getLetterPosXRight ( characterSprite ) - startOfLine > _width )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
if ( ! _lineBreakWithoutSpaces )
2012-04-19 14:35:52 +08:00
{
last_word . push_back ( character ) ;
int found = cc_utf8_find_last_not_char ( multiline_string , ' ' ) ;
if ( found ! = - 1 )
cc_utf8_trim_ws ( & multiline_string ) ;
else
multiline_string . clear ( ) ;
if ( multiline_string . size ( ) > 0 )
multiline_string . push_back ( ' \n ' ) ;
line + + ;
start_line = false ;
startOfLine = - 1 ;
i + + ;
}
else
{
cc_utf8_trim_ws ( & last_word ) ;
last_word . push_back ( ' \n ' ) ;
multiline_string . insert ( multiline_string . end ( ) , last_word . begin ( ) , last_word . end ( ) ) ;
last_word . clear ( ) ;
start_word = false ;
start_line = false ;
startOfWord = - 1 ;
startOfLine = - 1 ;
line + + ;
2012-05-29 17:11:33 +08:00
if ( i > = stringLength )
2012-04-19 14:35:52 +08:00
break ;
if ( ! startOfWord )
{
2012-04-25 18:17:04 +08:00
startOfWord = getLetterPosXLeft ( characterSprite ) ;
2012-04-19 14:35:52 +08:00
start_word = true ;
}
if ( ! startOfLine )
{
startOfLine = startOfWord ;
start_line = true ;
}
j - - ;
}
continue ;
}
else
{
// Character is normal.
last_word . push_back ( character ) ;
i + + ;
continue ;
}
}
multiline_string . insert ( multiline_string . end ( ) , last_word . begin ( ) , last_word . end ( ) ) ;
2013-11-28 16:02:03 +08:00
size_t size = multiline_string . size ( ) ;
2012-04-19 14:35:52 +08:00
unsigned short * str_new = new unsigned short [ size + 1 ] ;
2013-12-27 15:06:16 +08:00
for ( size_t j = 0 ; j < size ; + + j )
2012-05-29 17:11:33 +08:00
{
2013-11-11 12:49:38 +08:00
str_new [ j ] = multiline_string [ j ] ;
2012-05-29 17:11:33 +08:00
}
2012-04-19 14:35:52 +08:00
2013-03-20 13:55:43 +08:00
str_new [ size ] = ' \0 ' ;
2012-04-19 14:35:52 +08:00
2013-03-20 13:55:43 +08:00
this - > setString ( str_new , false ) ;
CC_SAFE_DELETE_ARRAY ( str_new ) ;
2012-04-19 14:35:52 +08:00
}
// Step 2: Make alignment
2013-07-27 07:04:21 +08:00
if ( _alignment ! = TextHAlignment : : LEFT )
2012-04-19 14:35:52 +08:00
{
int i = 0 ;
int lineNumber = 0 ;
2013-06-15 14:03:30 +08:00
int str_len = cc_wcslen ( _string ) ;
2012-04-19 14:35:52 +08:00
vector < unsigned short > last_line ;
for ( int ctr = 0 ; ctr < = str_len ; + + ctr )
{
2013-06-15 14:03:30 +08:00
if ( _string [ ctr ] = = ' \n ' | | _string [ ctr ] = = 0 )
2012-04-19 14:35:52 +08:00
{
float lineWidth = 0.0f ;
2013-11-28 16:02:03 +08:00
size_t line_length = last_line . size ( ) ;
2012-09-06 14:09:29 +08:00
// if last line is empty we must just increase lineNumber and work with next line
2012-09-05 15:36:34 +08:00
if ( line_length = = 0 )
{
lineNumber + + ;
continue ;
}
2013-12-06 16:32:06 +08:00
int index = static_cast < int > ( i + line_length - 1 + lineNumber ) ;
2012-04-19 14:35:52 +08:00
if ( index < 0 ) continue ;
2013-07-09 05:38:14 +08:00
Sprite * lastChar = static_cast < Sprite * > ( getChildByTag ( index ) ) ;
2013-12-18 17:47:20 +08:00
if ( lastChar = = nullptr )
2012-04-25 18:17:04 +08:00
continue ;
2012-04-19 14:35:52 +08:00
lineWidth = lastChar - > getPosition ( ) . x + lastChar - > getContentSize ( ) . width / 2.0f ;
float shift = 0 ;
2013-06-15 14:03:30 +08:00
switch ( _alignment )
2012-04-19 14:35:52 +08:00
{
2013-07-27 07:04:21 +08:00
case TextHAlignment : : CENTER :
2012-04-19 14:35:52 +08:00
shift = getContentSize ( ) . width / 2.0f - lineWidth / 2.0f ;
break ;
2013-07-27 07:04:21 +08:00
case TextHAlignment : : RIGHT :
2012-04-19 14:35:52 +08:00
shift = getContentSize ( ) . width - lineWidth ;
2012-06-08 16:22:57 +08:00
break ;
2012-04-19 14:35:52 +08:00
default :
break ;
}
if ( shift ! = 0 )
{
for ( unsigned j = 0 ; j < line_length ; j + + )
{
index = i + j + lineNumber ;
if ( index < 0 ) continue ;
2013-07-09 05:38:14 +08:00
Sprite * characterSprite = static_cast < Sprite * > ( getChildByTag ( index ) ) ;
2013-07-12 14:11:55 +08:00
characterSprite - > setPosition ( characterSprite - > getPosition ( ) + Point ( shift , 0.0f ) ) ;
2012-04-19 14:35:52 +08:00
}
}
i + = line_length ;
lineNumber + + ;
last_line . clear ( ) ;
continue ;
}
2013-06-15 14:03:30 +08:00
last_line . push_back ( _string [ ctr ] ) ;
2012-04-19 14:35:52 +08:00
}
}
2012-03-22 09:46:07 +08:00
}
// LabelBMFont - Alignment
2013-07-27 07:04:21 +08:00
void LabelBMFont : : setAlignment ( TextHAlignment alignment )
2012-03-22 09:46:07 +08:00
{
2013-06-15 14:03:30 +08:00
this - > _alignment = alignment ;
2012-04-19 14:35:52 +08:00
updateLabel ( ) ;
2012-03-22 09:46:07 +08:00
}
2013-06-20 14:13:12 +08:00
void LabelBMFont : : setWidth ( float width )
2012-03-22 09:46:07 +08:00
{
2013-06-15 14:03:30 +08:00
this - > _width = width ;
2012-04-19 14:35:52 +08:00
updateLabel ( ) ;
2012-03-22 09:46:07 +08:00
}
2013-06-20 14:13:12 +08:00
void LabelBMFont : : setLineBreakWithoutSpace ( bool breakWithoutSpace )
2012-03-22 09:46:07 +08:00
{
2013-06-15 14:03:30 +08:00
_lineBreakWithoutSpaces = breakWithoutSpace ;
2012-04-19 14:35:52 +08:00
updateLabel ( ) ;
2012-03-20 15:04:53 +08:00
}
2010-08-12 17:39:25 +08:00
2013-06-20 14:13:12 +08:00
void LabelBMFont : : setScale ( float scale )
2012-04-25 18:08:23 +08:00
{
2013-06-20 14:13:12 +08:00
SpriteBatchNode : : setScale ( scale ) ;
2012-04-25 18:17:04 +08:00
updateLabel ( ) ;
2012-04-25 18:08:23 +08:00
}
2013-06-20 14:13:12 +08:00
void LabelBMFont : : setScaleX ( float scaleX )
2012-04-25 18:08:23 +08:00
{
2013-06-20 14:13:12 +08:00
SpriteBatchNode : : setScaleX ( scaleX ) ;
2012-04-25 18:17:04 +08:00
updateLabel ( ) ;
2012-04-25 18:08:23 +08:00
}
2013-06-20 14:13:12 +08:00
void LabelBMFont : : setScaleY ( float scaleY )
2012-04-25 18:08:23 +08:00
{
2013-06-20 14:13:12 +08:00
SpriteBatchNode : : setScaleY ( scaleY ) ;
2012-04-25 18:17:04 +08:00
updateLabel ( ) ;
2012-04-25 18:08:23 +08:00
}
2013-06-20 14:13:12 +08:00
float LabelBMFont : : getLetterPosXLeft ( Sprite * sp )
2012-04-25 18:08:23 +08:00
{
2013-06-15 14:03:30 +08:00
return sp - > getPosition ( ) . x * _scaleX - ( sp - > getContentSize ( ) . width * _scaleX * sp - > getAnchorPoint ( ) . x ) ;
2012-04-25 18:08:23 +08:00
}
2013-06-20 14:13:12 +08:00
float LabelBMFont : : getLetterPosXRight ( Sprite * sp )
2012-04-25 18:08:23 +08:00
{
2013-06-15 14:03:30 +08:00
return sp - > getPosition ( ) . x * _scaleX + ( sp - > getContentSize ( ) . width * _scaleX * sp - > getAnchorPoint ( ) . x ) ;
2012-04-25 18:08:23 +08:00
}
2012-06-12 14:33:53 +08:00
2012-06-15 15:10:40 +08:00
// LabelBMFont - FntFile
2013-11-15 09:19:16 +08:00
void LabelBMFont : : setFntFile ( const std : : string & fntFile )
2012-06-15 15:10:40 +08:00
{
2013-11-15 09:19:16 +08:00
if ( _fntFile . compare ( fntFile ) ! = 0 )
2012-06-15 15:10:40 +08:00
{
CCBMFontConfiguration * newConf = FNTConfigLoadFile ( fntFile ) ;
2013-07-20 13:01:27 +08:00
CCASSERT ( newConf , " CCLabelBMFont: Impossible to create font. Please check file " ) ;
2012-06-15 15:10:40 +08:00
2013-06-15 14:03:30 +08:00
_fntFile = fntFile ;
2012-06-15 15:10:40 +08:00
CC_SAFE_RETAIN ( newConf ) ;
2013-06-15 14:03:30 +08:00
CC_SAFE_RELEASE ( _configuration ) ;
_configuration = newConf ;
2012-06-15 15:10:40 +08:00
2013-11-07 19:11:09 +08:00
this - > setTexture ( Director : : getInstance ( ) - > getTextureCache ( ) - > addImage ( _configuration - > getAtlasName ( ) ) ) ;
2012-06-15 15:10:40 +08:00
this - > createFontChars ( ) ;
}
}
2013-11-15 09:19:16 +08:00
const std : : string & LabelBMFont : : getFntFile ( ) const
2012-06-15 15:10:40 +08:00
{
2013-11-15 09:19:16 +08:00
return _fntFile ;
2012-06-15 15:10:40 +08:00
}
2012-06-12 14:33:53 +08:00
2013-12-13 06:30:22 +08:00
std : : string LabelBMFont : : getDescription ( ) const
{
return StringUtils : : format ( " <LabelBMFont | Tag = %d, Label = '%s'> " , _tag , _initialStringUTF8 . c_str ( ) ) ;
}
2012-06-12 14:33:53 +08:00
2012-03-20 15:04:53 +08:00
//LabelBMFont - Debug draw
2011-07-04 10:59:35 +08:00
# if CC_LABELBMFONT_DEBUG_DRAW
2013-06-20 14:13:12 +08:00
void LabelBMFont : : draw ( )
2012-03-20 15:04:53 +08:00
{
2013-06-20 14:13:12 +08:00
SpriteBatchNode : : draw ( ) ;
const Size & s = this - > getContentSize ( ) ;
Point vertices [ 4 ] = {
2013-07-12 18:04:32 +08:00
Point ( 0 , 0 ) , Point ( s . width , 0 ) ,
Point ( s . width , s . height ) , Point ( 0 , s . height ) ,
2012-04-19 14:35:52 +08:00
} ;
ccDrawPoly ( vertices , 4 , true ) ;
2012-03-20 15:04:53 +08:00
}
2012-03-22 09:46:07 +08:00
2011-07-04 10:59:35 +08:00
# endif // CC_LABELBMFONT_DEBUG_DRAW
2011-11-09 22:11:36 +08:00
2012-03-20 15:04:53 +08:00
NS_CC_END