2013-11-07 09:05:13 +08:00
/****************************************************************************
Copyright ( c ) 2013 Zynga Inc .
2014-01-07 11:25:07 +08:00
Copyright ( c ) 2013 - 2014 Chukong Technologies Inc .
2013-11-07 09:05:13 +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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-07-26 08:58:13 +08:00
# include "CCFontFNT.h"
2014-02-20 22:33:52 +08:00
# include "uthash.h"
# include "CCConfiguration.h"
2014-01-17 13:35:58 +08:00
# include "CCDirector.h"
2014-02-20 22:33:52 +08:00
# include "CCFontAtlas.h"
# include "CCMap.h"
2014-04-09 22:30:49 +08:00
# include "deprecated/CCString.h"
2014-01-17 13:35:58 +08:00
# include "CCTextureCache.h"
# include "ccUTF8.h"
2014-02-20 22:33:52 +08:00
# include "platform/CCFileUtils.h"
2013-07-26 08:58:13 +08:00
2014-02-20 22:33:52 +08:00
using namespace std ;
2013-07-26 08:58:13 +08:00
NS_CC_BEGIN
2014-02-20 22:33:52 +08:00
/**
* @ addtogroup GUI
* @ {
* @ addtogroup label
* @ {
*/
enum {
kLabelAutomaticWidth = - 1 ,
} ;
struct _FontDefHashElement ;
/**
2014-02-21 09:59:43 +08:00
@ struct BMFontDef
2014-02-20 22:33:52 +08:00
BMFont definition
*/
typedef struct _BMFontDef {
//! ID of the character
unsigned int charID ;
//! origin and size of the font
Rect rect ;
//! The X amount the image should be offset when drawing the image (in pixels)
short xOffset ;
//! The Y amount the image should be offset when drawing the image (in pixels)
short yOffset ;
//! The amount to move the current position after drawing the character (in pixels)
short xAdvance ;
2014-02-21 09:59:43 +08:00
} BMFontDef ;
2014-02-20 22:33:52 +08:00
2014-02-21 09:59:43 +08:00
/** @struct BMFontPadding
2014-02-20 22:33:52 +08:00
BMFont padding
@ since v0 .8 .2
*/
typedef struct _BMFontPadding {
/// padding left
int left ;
/// padding top
int top ;
/// padding right
int right ;
/// padding bottom
int bottom ;
2014-02-21 09:59:43 +08:00
} BMFontPadding ;
2014-02-20 22:33:52 +08:00
typedef struct _FontDefHashElement
{
unsigned int key ; // key. Font Unicode value
2014-02-21 09:59:43 +08:00
BMFontDef fontDef ; // font definition
2014-02-20 22:33:52 +08:00
UT_hash_handle hh ;
} tFontDefHashElement ;
// Equal function for targetSet.
typedef struct _KerningHashElement
{
int key ; // key for the hash. 16-bit for 1st element, 16-bit for 2nd element
int amount ;
UT_hash_handle hh ;
} tKerningHashElement ;
2014-02-21 09:59:43 +08:00
/** @brief BMFontConfiguration has parsed configuration of the the .fnt file
2014-02-20 22:33:52 +08:00
@ since v0 .8
*/
2014-02-21 09:59:43 +08:00
class CC_DLL BMFontConfiguration : public Ref
2014-02-20 22:33:52 +08:00
{
// XXX: Creating a public interface so that the bitmapFontArray[] is accessible
public : //@public
// BMFont definitions
tFontDefHashElement * _fontDefDictionary ;
//! FNTConfig: Common Height Should be signed (issue #1343)
int _commonHeight ;
//! Padding
2014-02-21 09:59:43 +08:00
BMFontPadding _padding ;
2014-02-20 22:33:52 +08:00
//! atlas name
std : : string _atlasName ;
//! values for kerning
tKerningHashElement * _kerningDictionary ;
// Character Set defines the letters that actually exist in the font
std : : set < unsigned int > * _characterSet ;
public :
/**
* @ js ctor
*/
2014-02-21 09:59:43 +08:00
BMFontConfiguration ( ) ;
2014-02-20 22:33:52 +08:00
/**
* @ js NA
* @ lua NA
*/
2014-02-21 09:59:43 +08:00
virtual ~ BMFontConfiguration ( ) ;
2014-02-20 22:33:52 +08:00
/**
* @ js NA
* @ lua NA
*/
std : : string description ( ) const ;
2014-02-21 09:59:43 +08:00
/** allocates a BMFontConfiguration with a FNT file */
static BMFontConfiguration * create ( const std : : string & FNTfile ) ;
2014-02-20 22:33:52 +08:00
/** initializes a BitmapFontConfiguration with a FNT file */
bool initWithFNTfile ( const std : : string & FNTfile ) ;
inline const std : : string & getAtlasName ( ) { return _atlasName ; }
inline void setAtlasName ( const std : : string & atlasName ) { _atlasName = atlasName ; }
std : : set < unsigned int > * getCharacterSet ( ) const ;
private :
std : : set < unsigned int > * parseConfigFile ( const std : : string & controlFile ) ;
std : : set < unsigned int > * parseBinaryConfigFile ( unsigned char * pData , unsigned long size , const std : : string & controlFile ) ;
2014-02-21 09:59:43 +08:00
void parseCharacterDefinition ( std : : string line , BMFontDef * characterDefinition ) ;
2014-02-20 22:33:52 +08:00
void parseInfoArguments ( std : : string line ) ;
void parseCommonArguments ( std : : string line ) ;
void parseImageFileName ( std : : string line , const std : : string & fntFile ) ;
void parseKerningEntry ( std : : string line ) ;
void purgeKerningDictionary ( ) ;
void purgeFontDefDictionary ( ) ;
} ;
//
//FNTConfig Cache - free functions
//
2014-02-21 09:59:43 +08:00
static Map < std : : string , BMFontConfiguration * > * s_configurations = nullptr ;
2014-02-20 22:33:52 +08:00
2014-02-21 09:59:43 +08:00
BMFontConfiguration * FNTConfigLoadFile ( const std : : string & fntFile )
2014-02-20 22:33:52 +08:00
{
2014-02-21 09:59:43 +08:00
BMFontConfiguration * ret = nullptr ;
2014-02-20 22:33:52 +08:00
if ( s_configurations = = nullptr )
{
2014-02-21 09:59:43 +08:00
s_configurations = new Map < std : : string , BMFontConfiguration * > ( ) ;
2014-02-20 22:33:52 +08:00
}
ret = s_configurations - > at ( fntFile ) ;
if ( ret = = nullptr )
{
2014-02-21 09:59:43 +08:00
ret = BMFontConfiguration : : create ( fntFile . c_str ( ) ) ;
2014-02-20 22:33:52 +08:00
if ( ret )
{
s_configurations - > insert ( fntFile , ret ) ;
}
}
return ret ;
}
//
//BitmapFontConfiguration
//
2014-02-21 09:59:43 +08:00
BMFontConfiguration * BMFontConfiguration : : create ( const std : : string & FNTfile )
2014-02-20 22:33:52 +08:00
{
2014-02-21 09:59:43 +08:00
BMFontConfiguration * ret = new BMFontConfiguration ( ) ;
2014-02-20 22:33:52 +08:00
if ( ret - > initWithFNTfile ( FNTfile ) )
{
ret - > autorelease ( ) ;
return ret ;
}
CC_SAFE_DELETE ( ret ) ;
return nullptr ;
}
2014-02-21 09:59:43 +08:00
bool BMFontConfiguration : : initWithFNTfile ( const std : : string & FNTfile )
2014-02-20 22:33:52 +08:00
{
_kerningDictionary = nullptr ;
_fontDefDictionary = nullptr ;
_characterSet = this - > parseConfigFile ( FNTfile ) ;
if ( ! _characterSet )
{
return false ;
}
return true ;
}
2014-02-21 09:59:43 +08:00
std : : set < unsigned int > * BMFontConfiguration : : getCharacterSet ( ) const
2014-02-20 22:33:52 +08:00
{
return _characterSet ;
}
2014-02-21 09:59:43 +08:00
BMFontConfiguration : : BMFontConfiguration ( )
2014-02-20 22:33:52 +08:00
: _fontDefDictionary ( nullptr )
, _commonHeight ( 0 )
, _kerningDictionary ( nullptr )
, _characterSet ( nullptr )
{
}
2014-02-21 09:59:43 +08:00
BMFontConfiguration : : ~ BMFontConfiguration ( )
2014-02-20 22:33:52 +08:00
{
2014-02-21 09:59:43 +08:00
CCLOGINFO ( " deallocing BMFontConfiguration: %p " , this ) ;
2014-02-20 22:33:52 +08:00
this - > purgeFontDefDictionary ( ) ;
this - > purgeKerningDictionary ( ) ;
_atlasName . clear ( ) ;
CC_SAFE_DELETE ( _characterSet ) ;
}
2014-02-21 09:59:43 +08:00
std : : string BMFontConfiguration : : description ( void ) const
2014-02-20 22:33:52 +08:00
{
return StringUtils : : format (
2014-02-21 09:59:43 +08:00
" <BMFontConfiguration = " CC_FORMAT_PRINTF_SIZE_T " | Glphys:%d Kernings:%d | Image = %s> " ,
2014-02-20 22:33:52 +08:00
( size_t ) this ,
HASH_COUNT ( _fontDefDictionary ) ,
HASH_COUNT ( _kerningDictionary ) ,
_atlasName . c_str ( )
) ;
}
2014-02-21 09:59:43 +08:00
void BMFontConfiguration : : purgeKerningDictionary ( )
2014-02-20 22:33:52 +08:00
{
tKerningHashElement * current ;
while ( _kerningDictionary )
{
current = _kerningDictionary ;
HASH_DEL ( _kerningDictionary , current ) ;
free ( current ) ;
}
}
2014-02-21 09:59:43 +08:00
void BMFontConfiguration : : purgeFontDefDictionary ( )
2014-02-20 22:33:52 +08:00
{
tFontDefHashElement * current , * tmp ;
HASH_ITER ( hh , _fontDefDictionary , current , tmp ) {
HASH_DEL ( _fontDefDictionary , current ) ;
free ( current ) ;
}
}
2014-02-21 09:59:43 +08:00
std : : set < unsigned int > * BMFontConfiguration : : parseConfigFile ( const std : : string & controlFile )
2014-02-20 22:33:52 +08:00
{
std : : string fullpath = FileUtils : : getInstance ( ) - > fullPathForFilename ( controlFile ) ;
Data data = FileUtils : : getInstance ( ) - > getDataFromFile ( fullpath ) ;
2014-02-21 09:59:43 +08:00
CCASSERT ( ( ! data . isNull ( ) & & data . getSize ( ) > 0 ) , " BMFontConfiguration::parseConfigFile | Open file error. " ) ;
2014-02-20 22:33:52 +08:00
if ( memcmp ( " BMF " , data . getBytes ( ) , 3 ) = = 0 ) {
std : : set < unsigned int > * ret = parseBinaryConfigFile ( data . getBytes ( ) , data . getSize ( ) , controlFile ) ;
return ret ;
}
std : : string contents ( ( const char * ) data . getBytes ( ) , data . getSize ( ) ) ;
std : : set < unsigned int > * validCharsString = new std : : set < unsigned int > ( ) ;
if ( contents . empty ( ) )
{
CCLOG ( " cocos2d: Error parsing FNTfile %s " , controlFile . c_str ( ) ) ;
return nullptr ;
}
// parse spacing / padding
std : : string line ;
std : : string strLeft ( contents ) ;
while ( strLeft . length ( ) > 0 )
{
size_t pos = strLeft . find ( ' \n ' ) ;
if ( pos ! = std : : string : : npos )
{
// 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
tFontDefHashElement * element = ( tFontDefHashElement * ) malloc ( sizeof ( * element ) ) ;
this - > parseCharacterDefinition ( line , & element - > fontDef ) ;
element - > key = element - > fontDef . charID ;
HASH_ADD_INT ( _fontDefDictionary , key , element ) ;
validCharsString - > insert ( element - > fontDef . charID ) ;
}
// else if(line.substr(0,strlen("kernings count")) == "kernings count")
// {
// this->parseKerningCapacity(line);
// }
else if ( line . substr ( 0 , strlen ( " kerning first " ) ) = = " kerning first " )
{
this - > parseKerningEntry ( line ) ;
}
}
return validCharsString ;
}
2014-02-21 09:59:43 +08:00
std : : set < unsigned int > * BMFontConfiguration : : parseBinaryConfigFile ( unsigned char * pData , unsigned long size , const std : : string & controlFile )
2014-02-20 22:33:52 +08:00
{
/* 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 ;
CCASSERT ( pData [ 3 ] = = 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 ;
CCASSERT ( strlen ( value ) < 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 ;
}
2014-02-21 09:59:43 +08:00
void BMFontConfiguration : : parseImageFileName ( std : : string line , const std : : string & fntFile )
2014-02-20 22:33:52 +08:00
{
//////////////////////////////////////////////////////////////////////////
// line to parse:
// page id=0 file="bitmapFontTest.png"
//////////////////////////////////////////////////////////////////////////
// page ID. Sanity check
auto index = line . find ( ' = ' ) + 1 ;
auto index2 = line . find ( ' ' , index ) ;
std : : string value = line . substr ( index , index2 - index ) ;
CCASSERT ( atoi ( value . c_str ( ) ) = = 0 , " LabelBMFont file could not be found " ) ;
// file
index = line . find ( ' " ' ) + 1 ;
index2 = line . find ( ' " ' , index ) ;
value = line . substr ( index , index2 - index ) ;
_atlasName = FileUtils : : getInstance ( ) - > fullPathFromRelativeFile ( value . c_str ( ) , fntFile ) ;
}
2014-02-21 09:59:43 +08:00
void BMFontConfiguration : : parseInfoArguments ( std : : string line )
2014-02-20 22:33: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
auto index = line . find ( " padding= " ) ;
auto index2 = line . find ( ' ' , index ) ;
std : : string value = line . substr ( index , index2 - index ) ;
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 ) ;
}
2014-02-21 09:59:43 +08:00
void BMFontConfiguration : : parseCommonArguments ( std : : string line )
2014-02-20 22:33:52 +08:00
{
//////////////////////////////////////////////////////////////////////////
// line to parse:
// common lineHeight=104 base=26 scaleW=1024 scaleH=512 pages=1 packed=0
//////////////////////////////////////////////////////////////////////////
// Height
auto index = line . find ( " lineHeight= " ) ;
auto index2 = line . find ( ' ' , index ) ;
std : : string value = line . substr ( index , index2 - index ) ;
sscanf ( value . c_str ( ) , " lineHeight=%d " , & _commonHeight ) ;
// scaleW. sanity check
index = line . find ( " scaleW= " ) + strlen ( " scaleW= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
CCASSERT ( atoi ( value . c_str ( ) ) < = Configuration : : getInstance ( ) - > getMaxTextureSize ( ) , " CCLabelBMFont: page can't be larger than supported " ) ;
// scaleH. sanity check
index = line . find ( " scaleH= " ) + strlen ( " scaleH= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
CCASSERT ( atoi ( value . c_str ( ) ) < = Configuration : : getInstance ( ) - > getMaxTextureSize ( ) , " CCLabelBMFont: page can't be larger than supported " ) ;
// pages. sanity check
index = line . find ( " pages= " ) + strlen ( " pages= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
CCASSERT ( atoi ( value . c_str ( ) ) = = 1 , " CCBitfontAtlas: only supports 1 page " ) ;
// packed (ignore) What does this mean ??
}
2014-02-21 09:59:43 +08:00
void BMFontConfiguration : : parseCharacterDefinition ( std : : string line , BMFontDef * characterDefinition )
2014-02-20 22:33: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
auto index = line . find ( " id= " ) ;
auto index2 = line . find ( ' ' , index ) ;
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 ) ;
sscanf ( value . c_str ( ) , " xoffset=%hd " , & characterDefinition - > xOffset ) ;
// Character yoffset
index = line . find ( " yoffset= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
sscanf ( value . c_str ( ) , " yoffset=%hd " , & characterDefinition - > yOffset ) ;
// Character xadvance
index = line . find ( " xadvance= " ) ;
index2 = line . find ( ' ' , index ) ;
value = line . substr ( index , index2 - index ) ;
sscanf ( value . c_str ( ) , " xadvance=%hd " , & characterDefinition - > xAdvance ) ;
}
2014-02-21 09:59:43 +08:00
void BMFontConfiguration : : parseKerningEntry ( std : : string line )
2014-02-20 22:33:52 +08:00
{
//////////////////////////////////////////////////////////////////////////
// line to parse:
// kerning first=121 second=44 amount=-7
//////////////////////////////////////////////////////////////////////////
// first
int first ;
auto index = line . find ( " first= " ) ;
auto index2 = line . find ( ' ' , index ) ;
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 ) ;
tKerningHashElement * element = ( tKerningHashElement * ) calloc ( sizeof ( * element ) , 1 ) ;
element - > amount = amount ;
element - > key = ( first < < 16 ) | ( second & 0xffff ) ;
HASH_ADD_INT ( _kerningDictionary , key , element ) ;
}
2014-04-15 18:13:57 +08:00
FontFNT * FontFNT : : create ( const std : : string & fntFilePath , const Vector2 & imageOffset /* = Vector2::ZERO */ )
2013-08-06 06:56:18 +08:00
{
2014-02-21 09:59:43 +08:00
BMFontConfiguration * newConf = FNTConfigLoadFile ( fntFilePath ) ;
2013-08-07 04:43:29 +08:00
if ( ! newConf )
return nullptr ;
// add the texture
2013-11-07 19:11:09 +08:00
Texture2D * tempTexture = Director : : getInstance ( ) - > getTextureCache ( ) - > addImage ( newConf - > getAtlasName ( ) ) ;
2013-09-13 11:46:46 +08:00
if ( ! tempTexture )
2013-08-07 04:43:29 +08:00
{
delete newConf ;
return nullptr ;
}
2014-02-20 22:33:52 +08:00
FontFNT * tempFont = new FontFNT ( newConf , imageOffset ) ;
2013-08-07 04:43:29 +08:00
if ( ! tempFont )
{
delete newConf ;
return nullptr ;
}
2013-10-31 20:17:30 +08:00
tempFont - > autorelease ( ) ;
2013-08-07 04:43:29 +08:00
return tempFont ;
2013-08-06 06:56:18 +08:00
}
2014-04-15 18:13:57 +08:00
FontFNT : : FontFNT ( BMFontConfiguration * theContfig , const Vector2 & imageOffset /* = Vector2::ZERO */ )
2014-02-20 22:33:52 +08:00
: _configuration ( theContfig )
, _imageOffset ( CC_POINT_PIXELS_TO_POINTS ( imageOffset ) )
{
}
2013-07-26 08:58:13 +08:00
FontFNT : : ~ FontFNT ( )
{
2013-10-31 17:52:22 +08:00
2013-07-26 08:58:13 +08:00
}
2014-02-20 22:33:52 +08:00
void FontFNT : : purgeCachedData ( )
{
if ( s_configurations )
{
s_configurations - > clear ( ) ;
CC_SAFE_DELETE ( s_configurations ) ;
}
}
2014-01-21 17:55:49 +08:00
int * FontFNT : : getHorizontalKerningForTextUTF16 ( unsigned short * text , int & outNumLetters ) const
2013-07-26 08:58:13 +08:00
{
2013-09-13 11:46:46 +08:00
if ( ! text )
2013-07-26 08:58:13 +08:00
return 0 ;
2013-09-13 11:46:46 +08:00
outNumLetters = cc_wcslen ( text ) ;
2013-07-26 08:58:13 +08:00
if ( ! outNumLetters )
return 0 ;
2014-01-21 17:55:49 +08:00
int * sizes = new int [ outNumLetters ] ;
2013-09-13 11:46:46 +08:00
if ( ! sizes )
2013-07-26 08:58:13 +08:00
return 0 ;
2013-09-13 11:46:46 +08:00
for ( int c = 0 ; c < outNumLetters ; + + c )
2013-07-26 08:58:13 +08:00
{
2013-09-13 11:46:46 +08:00
if ( c < ( outNumLetters - 1 ) )
2014-01-21 17:55:49 +08:00
sizes [ c ] = getHorizontalKerningForChars ( text [ c ] , text [ c + 1 ] ) ;
else
sizes [ c ] = 0 ;
2013-07-26 08:58:13 +08:00
}
2013-09-13 11:46:46 +08:00
return sizes ;
2013-07-26 08:58:13 +08:00
}
2013-09-13 11:46:46 +08:00
int FontFNT : : getHorizontalKerningForChars ( unsigned short firstChar , unsigned short secondChar ) const
2013-07-26 08:58:13 +08:00
{
int ret = 0 ;
2013-09-13 11:46:46 +08:00
unsigned int key = ( firstChar < < 16 ) | ( secondChar & 0xffff ) ;
2013-07-26 08:58:13 +08:00
2013-09-13 11:46:46 +08:00
if ( _configuration - > _kerningDictionary )
2013-07-26 08:58:13 +08:00
{
2013-09-13 11:46:46 +08:00
tKerningHashElement * element = nullptr ;
2013-07-26 08:58:13 +08:00
HASH_FIND_INT ( _configuration - > _kerningDictionary , & key , element ) ;
2013-09-13 11:46:46 +08:00
if ( element )
2013-07-26 08:58:13 +08:00
ret = element - > amount ;
}
return ret ;
}
2013-08-02 05:36:34 +08:00
FontAtlas * FontFNT : : createFontAtlas ( )
{
2013-08-06 08:49:20 +08:00
FontAtlas * tempAtlas = new FontAtlas ( * this ) ;
2013-08-02 05:36:34 +08:00
if ( ! tempAtlas )
return nullptr ;
// check that everything is fine with the BMFontCofniguration
if ( ! _configuration - > _fontDefDictionary )
return nullptr ;
2013-12-06 16:32:06 +08:00
size_t numGlyphs = _configuration - > _characterSet - > size ( ) ;
2013-08-02 05:36:34 +08:00
if ( ! numGlyphs )
return nullptr ;
if ( _configuration - > _commonHeight = = 0 )
return nullptr ;
// commone height
tempAtlas - > setCommonLineHeight ( _configuration - > _commonHeight ) ;
2014-02-21 09:59:43 +08:00
BMFontDef fontDef ;
2013-09-13 11:46:46 +08:00
tFontDefHashElement * currentElement , * tmp ;
2013-08-02 05:36:34 +08:00
// Purge uniform hash
2013-09-13 11:46:46 +08:00
HASH_ITER ( hh , _configuration - > _fontDefDictionary , currentElement , tmp )
2013-08-02 05:36:34 +08:00
{
FontLetterDefinition tempDefinition ;
2013-09-13 11:46:46 +08:00
fontDef = currentElement - > fontDef ;
2013-08-02 05:36:34 +08:00
Rect tempRect ;
tempRect = fontDef . rect ;
tempRect = CC_RECT_PIXELS_TO_POINTS ( tempRect ) ;
tempDefinition . letteCharUTF16 = fontDef . charID ;
tempDefinition . offsetX = fontDef . xOffset ;
tempDefinition . offsetY = fontDef . yOffset ;
2014-02-20 22:33:52 +08:00
tempDefinition . U = tempRect . origin . x + _imageOffset . x ;
tempDefinition . V = tempRect . origin . y + _imageOffset . y ;
2013-08-02 05:36:34 +08:00
tempDefinition . width = tempRect . size . width ;
tempDefinition . height = tempRect . size . height ;
//carloX: only one texture supported FOR NOW
tempDefinition . textureID = 0 ;
2013-10-29 20:25:03 +08:00
tempDefinition . validDefinition = true ;
2014-01-21 17:55:49 +08:00
tempDefinition . xAdvance = fontDef . xAdvance ;
2013-08-02 05:36:34 +08:00
// add the new definition
tempAtlas - > addLetterDefinition ( tempDefinition ) ;
}
// add the texture (only one texture for now)
2013-11-07 19:11:09 +08:00
Texture2D * tempTexture = Director : : getInstance ( ) - > getTextureCache ( ) - > addImage ( _configuration - > getAtlasName ( ) ) ;
2013-08-02 05:36:34 +08:00
if ( ! tempTexture )
return 0 ;
// add the texture
2014-03-05 16:51:16 +08:00
tempAtlas - > addTexture ( tempTexture , 0 ) ;
2013-08-02 05:36:34 +08:00
// done
return tempAtlas ;
}
2014-02-20 22:33:52 +08:00
NS_CC_END