2013-11-07 09:05:13 +08:00
/****************************************************************************
Copyright ( c ) 2013 Zynga Inc .
2016-03-24 23:05:22 +08:00
Copyright ( c ) 2013 - 2016 Chukong Technologies Inc .
2014-01-07 11:25:07 +08:00
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
2014-05-01 10:09:13 +08:00
# include "2d/CCFontFNT.h"
2014-08-29 15:39:52 +08:00
# include <set>
2014-05-17 05:36:00 +08:00
# include "base/uthash.h"
# include "2d/CCFontAtlas.h"
# include "platform/CCFileUtils.h"
2014-05-01 10:09:13 +08:00
# include "base/CCConfiguration.h"
2014-04-30 08:37:36 +08:00
# include "base/CCDirector.h"
2014-04-27 01:35:57 +08:00
# include "base/CCMap.h"
2016-06-15 15:01:26 +08:00
# include "base/ccUTF8.h"
2014-05-17 05:36:00 +08:00
# include "renderer/CCTextureCache.h"
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
{
2015-01-08 10:22:45 +08:00
unsigned int key ; // key. Font Unicode value
BMFontDef fontDef ; // font definition
UT_hash_handle hh ;
2014-02-20 22:33:52 +08:00
} tFontDefHashElement ;
// Equal function for targetSet.
typedef struct _KerningHashElement
{
2015-01-08 10:22:45 +08:00
int key ; // key for the hash. 16-bit for 1st element, 16-bit for 2nd element
int amount ;
UT_hash_handle hh ;
2014-02-20 22:33:52 +08:00
} tKerningHashElement ;
2015-11-04 16:09:58 +08:00
/** @brief BMFontConfiguration has parsed configuration of 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
{
2014-08-30 03:54:24 +08:00
// FIXME: Creating a public interface so that the bitmapFontArray[] is accessible
2014-02-20 22:33:52 +08:00
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 ;
2015-11-19 16:06:13 +08:00
//! Font Size
int _fontSize ;
2014-02-20 22:33:52 +08:00
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 ) ;
2015-01-08 10:22:45 +08:00
std : : set < unsigned int > * parseBinaryConfigFile ( unsigned char * pData , unsigned long size , const std : : string & controlFile ) ;
2015-01-24 16:23:30 +08:00
void parseCharacterDefinition ( const char * line , BMFontDef * characterDefinition ) ;
void parseInfoArguments ( const char * line ) ;
void parseCommonArguments ( const char * line ) ;
void parseImageFileName ( const char * line , const std : : string & fntFile ) ;
void parseKerningEntry ( const char * line ) ;
2014-02-20 22:33:52 +08:00
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-08-28 07:31:57 +08:00
s_configurations = new ( std : : nothrow ) Map < std : : string , BMFontConfiguration * > ( ) ;
2014-02-20 22:33:52 +08:00
}
ret = s_configurations - > at ( fntFile ) ;
if ( ret = = nullptr )
{
2016-02-03 23:12:37 +08:00
ret = BMFontConfiguration : : create ( fntFile ) ;
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-08-28 07:31:57 +08:00
BMFontConfiguration * ret = new ( std : : nothrow ) 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 ) ;
2015-01-24 16:23:30 +08:00
2014-02-20 22:33:52 +08:00
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 )
2015-11-19 16:06:13 +08:00
, _fontSize ( 0 )
2014-02-20 22:33:52 +08:00
{
}
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 )
2015-01-24 16:23:30 +08:00
{
Data data = FileUtils : : getInstance ( ) - > getDataFromFile ( controlFile ) ;
CCASSERT ( ( ! data . isNull ( ) ) , " BMFontConfiguration::parseConfigFile | Open file error. " ) ;
2016-03-24 23:05:22 +08:00
if ( data . isNull ( ) ) {
return nullptr ;
}
2014-02-20 22:33:52 +08:00
if ( memcmp ( " BMF " , data . getBytes ( ) , 3 ) = = 0 ) {
2016-01-15 00:48:33 +08:00
// Handle fnt file of binary format
2014-02-20 22:33:52 +08:00
std : : set < unsigned int > * ret = parseBinaryConfigFile ( data . getBytes ( ) , data . getSize ( ) , controlFile ) ;
return ret ;
}
2016-01-15 00:48:33 +08:00
if ( data . getBytes ( ) [ 0 ] = = 0 )
2014-02-20 22:33:52 +08:00
{
CCLOG ( " cocos2d: Error parsing FNTfile %s " , controlFile . c_str ( ) ) ;
return nullptr ;
}
2016-01-15 00:48:33 +08:00
// Handle fnt file of string format, allocate one extra byte '\0' at the end since c string needs it.
// 'strchr' finds a char until it gets a '\0', if 'contents' self doesn't end with '\0',
// 'strchr' will search '\n' out of 'contents' 's buffer size, it will trigger potential and random crashes since
// lineLength may bigger than 512 and 'memcpy(line, contents + parseCount, lineLength);' will cause stack buffer overflow.
// Please note that 'contents' needs to be freed before this function returns.
2016-03-24 23:05:22 +08:00
auto contents = ( char * ) malloc ( data . getSize ( ) + 1 ) ;
2016-01-15 00:48:33 +08:00
if ( contents = = nullptr )
{
CCLOGERROR ( " BMFontConfiguration::parseConfigFile, out of memory! " ) ;
return nullptr ;
}
memcpy ( contents , data . getBytes ( ) , data . getSize ( ) ) ;
// Ensure the last byte is '\0'
contents [ data . getSize ( ) ] = ' \0 ' ;
2015-12-16 14:02:55 +08:00
std : : set < unsigned int > * validCharsString = new ( std : : nothrow ) std : : set < unsigned int > ( ) ;
2015-01-24 16:23:30 +08:00
2016-01-15 00:48:33 +08:00
auto contentsLen = strlen ( contents ) ;
char line [ 512 ] = { 0 } ;
2015-01-24 16:23:30 +08:00
auto next = strchr ( contents , ' \n ' ) ;
auto base = contents ;
2016-04-26 14:50:39 +08:00
size_t lineLength = 0 ;
size_t parseCount = 0 ;
2015-01-24 16:23:30 +08:00
while ( next )
2014-02-20 22:33:52 +08:00
{
2015-04-21 10:57:55 +08:00
lineLength = ( ( int ) ( next - base ) ) ;
2015-01-24 16:23:30 +08:00
memcpy ( line , contents + parseCount , lineLength ) ;
line [ lineLength ] = 0 ;
2014-02-20 22:33:52 +08:00
2015-01-24 16:23:30 +08:00
parseCount + = lineLength + 1 ;
if ( parseCount < contentsLen )
2014-02-20 22:33:52 +08:00
{
2015-01-24 16:23:30 +08:00
base = next + 1 ;
next = strchr ( base , ' \n ' ) ;
}
2014-02-20 22:33:52 +08:00
else
{
2015-01-24 16:23:30 +08:00
next = nullptr ;
2014-02-20 22:33:52 +08:00
}
2015-01-24 16:23:30 +08:00
if ( memcmp ( line , " info face " , 9 ) = = 0 )
2014-02-20 22:33:52 +08:00
{
2014-08-30 03:54:24 +08:00
// FIXME: info parsing is incomplete
2014-02-20 22:33:52 +08:00
// 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
2015-01-24 16:23:30 +08:00
else if ( memcmp ( line , " common lineHeight " , 17 ) = = 0 )
2014-02-20 22:33:52 +08:00
{
this - > parseCommonArguments ( line ) ;
}
2015-01-24 16:23:30 +08:00
else if ( memcmp ( line , " page id " , 7 ) = = 0 )
2014-02-20 22:33:52 +08:00
{
this - > parseImageFileName ( line , controlFile ) ;
}
2015-01-24 16:23:30 +08:00
else if ( memcmp ( line , " chars c " , 7 ) = = 0 )
2014-02-20 22:33:52 +08:00
{
// Ignore this line
}
2015-01-24 16:23:30 +08:00
else if ( memcmp ( line , " char " , 4 ) = = 0 )
2014-02-20 22:33:52 +08:00
{
// 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 ) ;
}
2015-01-24 16:23:30 +08:00
else if ( memcmp ( line , " kerning first " , 13 ) = = 0 )
2014-02-20 22:33:52 +08:00
{
this - > parseKerningEntry ( line ) ;
}
}
2016-01-15 00:48:33 +08:00
CC_SAFE_FREE ( contents ) ;
2014-02-20 22:33:52 +08:00
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 */
2015-12-16 14:02:55 +08:00
set < unsigned int > * validCharsString = new ( std : : nothrow ) set < unsigned int > ( ) ;
2014-02-20 22:33:52 +08:00
unsigned long remains = size ;
CCASSERT ( pData [ 3 ] = = 3 , " Only version 3 is supported " ) ;
pData + = 4 ; remains - = 4 ;
while ( remains > 0 )
2015-01-08 10:22:45 +08:00
{
2014-02-20 22:33:52 +08:00
unsigned char blockId = pData [ 0 ] ; pData + = 1 ; remains - = 1 ;
uint32_t blockSize = 0 ; memcpy ( & blockSize , pData , 4 ) ;
pData + = 4 ; remains - = 4 ;
if ( blockId = = 1 )
2015-01-08 10:22:45 +08:00
{
2014-02-20 22:33:52 +08:00
/*
2015-01-08 10:22:45 +08:00
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
2014-02-20 22:33:52 +08:00
*/
2016-02-13 03:21:18 +08:00
memcpy ( & _fontSize , pData , 2 ) ;
2014-02-20 22:33:52 +08:00
_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 )
{
/*
2015-01-08 10:22:45 +08:00
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
2014-02-20 22:33:52 +08:00
*/
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 " ) ;
}
2015-01-08 10:22:45 +08:00
else if ( blockId = = 3 )
{
2014-02-20 22:33:52 +08:00
/*
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 )
{
/*
2015-01-08 10:22:45 +08:00
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
2014-02-20 22:33:52 +08:00
*/
unsigned long count = blockSize / 20 ;
for ( unsigned long i = 0 ; i < count ; i + + )
2015-01-08 10:22:45 +08:00
{
2014-02-20 22:33:52 +08:00
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 ) ;
}
}
2015-01-08 10:22:45 +08:00
else if ( blockId = = 5 ) {
2014-02-20 22:33:52 +08:00
/*
2015-01-08 10:22:45 +08:00
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
2014-02-20 22:33:52 +08:00
*/
unsigned long count = blockSize / 20 ;
for ( unsigned long i = 0 ; i < count ; i + + )
2015-01-08 10:22:45 +08:00
{
2014-02-20 22:33:52 +08:00
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 ;
}
2015-01-24 16:23:30 +08:00
void BMFontConfiguration : : parseImageFileName ( const char * 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
2015-01-24 16:23:30 +08:00
int pageId ;
sscanf ( line , " page id=%d " , & pageId ) ;
CCASSERT ( pageId = = 0 , " LabelBMFont file could not be found " ) ;
2014-02-20 22:33:52 +08:00
// file
2015-01-24 16:23:30 +08:00
char fileName [ 255 ] ;
sscanf ( strchr ( line , ' " ' ) + 1 , " %[^ \" ] " , fileName ) ;
_atlasName = FileUtils : : getInstance ( ) - > fullPathFromRelativeFile ( fileName , fntFile ) ;
2014-02-20 22:33:52 +08:00
}
2015-01-24 16:23:30 +08:00
void BMFontConfiguration : : parseInfoArguments ( const char * 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
//////////////////////////////////////////////////////////////////////////
2015-11-19 16:06:13 +08:00
sscanf ( strstr ( line , " size= " ) + 5 , " %d " , & _fontSize ) ;
2014-02-20 22:33:52 +08:00
// padding
2015-01-24 16:23:30 +08:00
sscanf ( strstr ( line , " padding= " ) + 8 , " %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-20 22:33:52 +08:00
}
2015-01-24 16:23:30 +08:00
void BMFontConfiguration : : parseCommonArguments ( const char * 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
//////////////////////////////////////////////////////////////////////////
2015-01-24 16:23:30 +08:00
2014-02-20 22:33:52 +08:00
// Height
2015-01-24 16:23:30 +08:00
auto tmp = strstr ( line , " lineHeight= " ) + 11 ;
sscanf ( tmp , " %d " , & _commonHeight ) ;
2016-03-24 23:05:22 +08:00
# if COCOS2D_DEBUG > 0
2014-02-20 22:33:52 +08:00
// scaleW. sanity check
2015-01-24 16:23:30 +08:00
int value ;
tmp = strstr ( tmp , " scaleW= " ) + 7 ;
sscanf ( tmp , " %d " , & value ) ;
int maxTextureSize = Configuration : : getInstance ( ) - > getMaxTextureSize ( ) ;
CCASSERT ( value < = maxTextureSize , " CCLabelBMFont: page can't be larger than supported " ) ;
2014-02-20 22:33:52 +08:00
// scaleH. sanity check
2015-01-24 16:23:30 +08:00
tmp = strstr ( tmp , " scaleH= " ) + 7 ;
sscanf ( tmp , " %d " , & value ) ;
CCASSERT ( value < = maxTextureSize , " CCLabelBMFont: page can't be larger than supported " ) ;
2014-02-20 22:33:52 +08:00
// pages. sanity check
2015-01-24 16:23:30 +08:00
tmp = strstr ( tmp , " pages= " ) + 6 ;
sscanf ( tmp , " %d " , & value ) ;
CCASSERT ( value = = 1 , " CCBitfontAtlas: only supports 1 page " ) ;
2016-03-24 23:05:22 +08:00
# endif
2014-02-20 22:33:52 +08:00
// packed (ignore) What does this mean ??
}
2015-01-24 16:23:30 +08:00
void BMFontConfiguration : : parseCharacterDefinition ( const char * 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
2015-01-24 16:23:30 +08:00
auto tmp = strstr ( line , " id= " ) + 3 ;
sscanf ( tmp , " %u " , & characterDefinition - > charID ) ;
2014-02-20 22:33:52 +08:00
// Character x
2015-01-24 16:23:30 +08:00
tmp = strstr ( tmp , " x= " ) + 2 ;
sscanf ( tmp , " %f " , & characterDefinition - > rect . origin . x ) ;
2014-02-20 22:33:52 +08:00
// Character y
2015-01-24 16:23:30 +08:00
tmp = strstr ( tmp , " y= " ) + 2 ;
sscanf ( tmp , " %f " , & characterDefinition - > rect . origin . y ) ;
2014-02-20 22:33:52 +08:00
// Character width
2015-01-24 16:23:30 +08:00
tmp = strstr ( tmp , " width= " ) + 6 ;
sscanf ( tmp , " %f " , & characterDefinition - > rect . size . width ) ;
2014-02-20 22:33:52 +08:00
// Character height
2015-01-24 16:23:30 +08:00
tmp = strstr ( tmp , " height= " ) + 7 ;
sscanf ( tmp , " %f " , & characterDefinition - > rect . size . height ) ;
2014-02-20 22:33:52 +08:00
// Character xoffset
2015-01-24 16:23:30 +08:00
tmp = strstr ( tmp , " xoffset= " ) + 8 ;
sscanf ( tmp , " %hd " , & characterDefinition - > xOffset ) ;
2014-02-20 22:33:52 +08:00
// Character yoffset
2015-01-24 16:23:30 +08:00
tmp = strstr ( tmp , " yoffset= " ) + 8 ;
sscanf ( tmp , " %hd " , & characterDefinition - > yOffset ) ;
2014-02-20 22:33:52 +08:00
// Character xadvance
2015-01-24 16:23:30 +08:00
tmp = strstr ( tmp , " xadvance= " ) + 9 ;
sscanf ( tmp , " %hd " , & characterDefinition - > xAdvance ) ;
2014-02-20 22:33:52 +08:00
}
2015-01-24 16:23:30 +08:00
void BMFontConfiguration : : parseKerningEntry ( const char * line )
2014-02-20 22:33:52 +08:00
{
//////////////////////////////////////////////////////////////////////////
// line to parse:
// kerning first=121 second=44 amount=-7
//////////////////////////////////////////////////////////////////////////
2015-01-24 16:23:30 +08:00
int first , second , amount ;
auto tmp = strstr ( line , " first= " ) + 6 ;
sscanf ( tmp , " %d " , & first ) ;
tmp = strstr ( tmp , " second= " ) + 7 ;
sscanf ( tmp , " %d " , & second ) ;
tmp = strstr ( tmp , " amount= " ) + 7 ;
sscanf ( tmp , " %d " , & amount ) ;
2014-02-20 22:33:52 +08:00
tKerningHashElement * element = ( tKerningHashElement * ) calloc ( sizeof ( * element ) , 1 ) ;
element - > amount = amount ;
element - > key = ( first < < 16 ) | ( second & 0xffff ) ;
HASH_ADD_INT ( _kerningDictionary , key , element ) ;
}
2014-05-15 01:07:09 +08:00
FontFNT * FontFNT : : create ( const std : : string & fntFilePath , const Vec2 & imageOffset /* = Vec2::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
{
return nullptr ;
}
2014-02-20 22:33:52 +08:00
FontFNT * tempFont = new FontFNT ( newConf , imageOffset ) ;
2015-11-19 16:06:13 +08:00
tempFont - > setFontSize ( newConf - > _fontSize ) ;
2013-08-07 04:43:29 +08:00
if ( ! tempFont )
{
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-05-15 01:07:09 +08:00
FontFNT : : FontFNT ( BMFontConfiguration * theContfig , const Vec2 & imageOffset /* = Vec2::ZERO */ )
2014-02-20 22:33:52 +08:00
: _configuration ( theContfig )
, _imageOffset ( CC_POINT_PIXELS_TO_POINTS ( imageOffset ) )
{
2015-01-08 10:22:45 +08:00
_configuration - > retain ( ) ;
2014-02-20 22:33:52 +08:00
}
2013-07-26 08:58:13 +08:00
FontFNT : : ~ FontFNT ( )
{
2015-01-08 10:22:45 +08:00
_configuration - > release ( ) ;
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-05-08 11:12:59 +08:00
int * FontFNT : : getHorizontalKerningForTextUTF16 ( const std : : u16string & text , int & outNumLetters ) const
2013-07-26 08:58:13 +08:00
{
2014-05-08 11:12:59 +08:00
outNumLetters = static_cast < int > ( text . length ( ) ) ;
2013-07-26 08:58:13 +08:00
if ( ! outNumLetters )
return 0 ;
2015-12-16 14:02:55 +08:00
int * sizes = new ( std : : nothrow ) 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 ;
}
2015-11-19 16:06:13 +08:00
void FontFNT : : setFontSize ( float fontSize )
{
_fontSize = fontSize ;
}
int FontFNT : : getOriginalFontSize ( ) const
{
return _configuration - > _fontSize ;
}
2013-08-02 05:36:34 +08:00
FontAtlas * FontFNT : : createFontAtlas ( )
{
// check that everything is fine with the BMFontCofniguration
2016-03-24 23:05:22 +08:00
if ( ! _configuration - > _fontDefDictionary )
2013-08-02 05:36:34 +08:00
return nullptr ;
2013-12-06 16:32:06 +08:00
size_t numGlyphs = _configuration - > _characterSet - > size ( ) ;
2016-03-24 23:05:22 +08:00
if ( numGlyphs = = 0 )
2013-08-02 05:36:34 +08:00
return nullptr ;
2016-03-24 23:05:22 +08:00
if ( _configuration - > _commonHeight = = 0 )
return nullptr ;
FontAtlas * tempAtlas = new ( std : : nothrow ) FontAtlas ( * this ) ;
if ( tempAtlas = = nullptr )
2013-08-02 05:36:34 +08:00
return nullptr ;
2015-09-22 16:08:23 +08:00
// common height
2015-11-19 16:06:13 +08:00
int originalFontSize = _configuration - > _fontSize ;
float originalLineHeight = _configuration - > _commonHeight ;
float factor = 0.0f ;
if ( fabs ( _fontSize - originalFontSize ) < FLT_EPSILON ) {
factor = 1.0f ;
} else {
factor = _fontSize / originalFontSize ;
}
tempAtlas - > setLineHeight ( originalLineHeight * factor ) ;
2013-08-02 05:36:34 +08:00
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 . 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
2016-04-25 00:02:50 +08:00
if ( 65535 < fontDef . charID ) {
CCLOGWARN ( " Warning: 65535 < fontDef.charID (%u), ignored " , fontDef . charID ) ;
} else {
tempAtlas - > addLetterDefinition ( fontDef . charID , tempDefinition ) ;
}
2013-08-02 05:36:34 +08:00
}
// add the texture (only one texture for now)
2013-11-07 19:11:09 +08:00
Texture2D * tempTexture = Director : : getInstance ( ) - > getTextureCache ( ) - > addImage ( _configuration - > getAtlasName ( ) ) ;
2015-10-26 14:53:36 +08:00
if ( ! tempTexture ) {
CC_SAFE_RELEASE ( tempAtlas ) ;
return nullptr ;
}
2013-08-02 05:36:34 +08:00
// 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 ;
}
2015-11-12 09:49:49 +08:00
void FontFNT : : reloadBMFontResource ( const std : : string & fntFilePath )
{
if ( s_configurations = = nullptr )
{
s_configurations = new ( std : : nothrow ) Map < std : : string , BMFontConfiguration * > ( ) ;
}
BMFontConfiguration * ret = s_configurations - > at ( fntFilePath ) ;
if ( ret ! = nullptr )
{
s_configurations - > erase ( fntFilePath ) ;
}
2016-02-03 23:12:37 +08:00
ret = BMFontConfiguration : : create ( fntFilePath ) ;
2015-11-12 09:49:49 +08:00
if ( ret )
{
s_configurations - > insert ( fntFilePath , ret ) ;
2015-12-13 18:36:52 +08:00
Director : : getInstance ( ) - > getTextureCache ( ) - > reloadTexture ( ret - > getAtlasName ( ) ) ;
2015-11-12 09:49:49 +08:00
}
}
2013-08-02 05:36:34 +08:00
2014-02-20 22:33:52 +08:00
NS_CC_END