2013-11-07 09:05:13 +08:00
/****************************************************************************
Copyright ( c ) 2013 Zynga Inc .
2018-01-29 16:25:32 +08:00
Copyright ( c ) 2013 - 2016 Chukong Technologies Inc .
Copyright ( c ) 2017 - 2018 Xiamen Yaji Software Co . , Ltd .
2021-10-11 12:15:41 +08:00
Copyright ( c ) 2021 Bytedance Inc .
https : //adxe.org
2013-11-07 09:05:13 +08:00
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-05-17 05:36:00 +08:00
# include "2d/CCFontAtlas.h"
2020-01-06 09:35:52 +08:00
# include "2d/CCSpriteFrameCache.h"
2014-05-17 05:36:00 +08:00
# 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"
2016-10-17 13:53:54 +08:00
# include <cmath>
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 ;
//
//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
2016-10-17 13:53:54 +08:00
if ( s_configurations = = nullptr )
2014-02-20 22:33:52 +08:00
{
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
{
_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 ( )
2016-10-17 13:53:54 +08:00
: _commonHeight ( 0 )
2014-02-20 22:33:52 +08:00
, _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 ) ;
}
2019-07-22 09:38:46 +08:00
std : : string BMFontConfiguration : : description ( ) 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 ,
2016-10-17 13:53:54 +08:00
static_cast < int > ( _fontDefDictionary . size ( ) ) ,
static_cast < int > ( _kerningDictionary . size ( ) ) ,
2014-02-20 22:33:52 +08:00
_atlasName . c_str ( )
) ;
}
2014-02-21 09:59:43 +08:00
void BMFontConfiguration : : purgeKerningDictionary ( )
2014-02-20 22:33:52 +08:00
{
2016-10-17 13:53:54 +08:00
_kerningDictionary . clear ( ) ;
2014-02-20 22:33:52 +08:00
}
2014-02-21 09:59:43 +08:00
void BMFontConfiguration : : purgeFontDefDictionary ( )
2016-10-17 13:53:54 +08:00
{
_fontDefDictionary . clear ( ) ;
2014-02-20 22:33:52 +08:00
}
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
{
2016-09-19 11:49:35 +08:00
std : : string data = FileUtils : : getInstance ( ) - > getStringFromFile ( controlFile ) ;
if ( data . empty ( ) )
2016-06-21 10:52:25 +08:00
{
2016-03-24 23:05:22 +08:00
return nullptr ;
}
2016-06-21 10:52:25 +08:00
if ( data . size ( ) > = ( sizeof ( " BMP " ) - 1 ) & & memcmp ( " BMF " , data . c_str ( ) , sizeof ( " BMP " ) - 1 ) = = 0 ) {
2016-01-15 00:48:33 +08:00
// Handle fnt file of binary format
2016-06-21 10:52:25 +08:00
std : : set < unsigned int > * ret = parseBinaryConfigFile ( ( unsigned char * ) & data . front ( ) , data . size ( ) , controlFile ) ;
2014-02-20 22:33:52 +08:00
return ret ;
}
2016-06-21 10:52:25 +08:00
if ( data [ 0 ] = = 0 )
2014-02-20 22:33:52 +08:00
{
CCLOG ( " cocos2d: Error parsing FNTfile %s " , controlFile . c_str ( ) ) ;
return nullptr ;
}
2016-06-21 10:52:25 +08:00
auto contents = data . c_str ( ) ;
2016-01-15 00:48:33 +08:00
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 parseCount = 0 ;
2015-01-24 16:23:30 +08:00
while ( next )
2014-02-20 22:33:52 +08:00
{
2021-10-11 12:15:41 +08:00
size_t 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
2016-10-17 13:53:54 +08:00
unsigned int charID = this - > parseCharacterDefinition ( line ) ;
validCharsString - > insert ( charID ) ;
2014-02-20 22:33:52 +08:00
}
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 ) ;
}
}
return validCharsString ;
}
2021-09-02 13:39:28 +08:00
std : : set < unsigned int > * BMFontConfiguration : : parseBinaryConfigFile ( unsigned char * pData , uint32_t 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 */
2016-10-17 13:53:54 +08:00
std : : set < unsigned int > * validCharsString = new ( std : : nothrow ) std : : set < unsigned int > ( ) ;
2014-02-20 22:33:52 +08:00
2021-09-02 13:39:28 +08:00
uint32_t remains = size ;
2014-02-20 22:33:52 +08:00
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
2016-07-22 01:05:19 +08:00
bitField 1 bits 2 bit 0 : smooth , bit 1 : unicode , bit 2 : italic , bit 3 : bold , bit 4 : fixedHeight , bits 5 - 7 : reserved
2015-01-08 10:22:45 +08:00
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
*/
2021-09-02 13:39:28 +08:00
uint32_t count = blockSize / 20 ;
2014-02-20 22:33:52 +08:00
2021-09-02 13:39:28 +08:00
for ( uint32_t i = 0 ; i < count ; i + + )
2015-01-08 10:22:45 +08:00
{
2014-02-20 22:33:52 +08:00
uint32_t charId = 0 ; memcpy ( & charId , pData + ( i * 20 ) , 4 ) ;
2016-10-17 13:53:54 +08:00
BMFontDef & fontDef = _fontDefDictionary [ charId ] ;
fontDef . charID = charId ;
2014-02-20 22:33:52 +08:00
uint16_t charX = 0 ; memcpy ( & charX , pData + ( i * 20 ) + 4 , 2 ) ;
2016-10-17 13:53:54 +08:00
fontDef . rect . origin . x = charX ;
2014-02-20 22:33:52 +08:00
uint16_t charY = 0 ; memcpy ( & charY , pData + ( i * 20 ) + 6 , 2 ) ;
2016-10-17 13:53:54 +08:00
fontDef . rect . origin . y = charY ;
2014-02-20 22:33:52 +08:00
uint16_t charWidth = 0 ; memcpy ( & charWidth , pData + ( i * 20 ) + 8 , 2 ) ;
2016-10-17 13:53:54 +08:00
fontDef . rect . size . width = charWidth ;
2014-02-20 22:33:52 +08:00
uint16_t charHeight = 0 ; memcpy ( & charHeight , pData + ( i * 20 ) + 10 , 2 ) ;
2016-10-17 13:53:54 +08:00
fontDef . rect . size . height = charHeight ;
2014-02-20 22:33:52 +08:00
int16_t xoffset = 0 ; memcpy ( & xoffset , pData + ( i * 20 ) + 12 , 2 ) ;
2016-10-17 13:53:54 +08:00
fontDef . xOffset = xoffset ;
2014-02-20 22:33:52 +08:00
int16_t yoffset = 0 ; memcpy ( & yoffset , pData + ( i * 20 ) + 14 , 2 ) ;
2016-10-17 13:53:54 +08:00
fontDef . yOffset = yoffset ;
2014-02-20 22:33:52 +08:00
int16_t xadvance = 0 ; memcpy ( & xadvance , pData + ( i * 20 ) + 16 , 2 ) ;
2016-10-17 13:53:54 +08:00
fontDef . xAdvance = xadvance ;
2014-02-20 22:33:52 +08:00
2016-10-17 13:53:54 +08:00
validCharsString - > insert ( fontDef . charID ) ;
2014-02-20 22:33:52 +08:00
}
}
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
*/
2021-09-02 13:39:28 +08:00
uint32_t count = blockSize / 20 ;
2014-02-20 22:33:52 +08:00
2021-09-02 13:39:28 +08:00
for ( uint32_t 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 ) ;
2017-02-06 16:41:52 +08:00
uint64_t key = ( ( uint64_t ) first < < 32 ) | ( ( uint64_t ) second & 0xffffffffll ) ;
2016-10-17 13:53:54 +08:00
_kerningDictionary [ key ] = amount ;
2014-02-20 22:33:52 +08:00
}
}
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 " ) ;
2020-01-06 09:35:52 +08:00
2014-02-20 22:33:52 +08:00
// file
2015-01-24 16:23:30 +08:00
char fileName [ 255 ] ;
2020-01-06 09:35:52 +08:00
sscanf ( strstr ( line , " file= \" " ) + 6 , " %[^ \" ] " , fileName ) ;
2015-01-24 16:23:30 +08:00
_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 ) ;
2019-05-16 09:26:00 +08:00
int maxTextureSize = Configuration : : getInstance ( ) - > getMaxTextureSize ( ) ;
2019-03-14 15:58:55 +08:00
CCASSERT ( value < = maxTextureSize , " CCLabelBMFont: page can't be larger than supported " ) ;
2015-01-24 16:23:30 +08:00
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 ) ;
2019-03-14 15:58:55 +08:00
CCASSERT ( value < = maxTextureSize , " CCLabelBMFont: page can't be larger than supported " ) ;
2015-01-24 16:23:30 +08:00
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 ??
}
2016-10-17 13:53:54 +08:00
unsigned int BMFontConfiguration : : parseCharacterDefinition ( const char * line )
{
unsigned int charID = 0 ;
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 ;
2016-10-17 13:53:54 +08:00
sscanf ( tmp , " %u " , & charID ) ;
BMFontDef & characterDefinition = _fontDefDictionary [ charID ] ;
characterDefinition . charID = charID ;
2014-02-20 22:33:52 +08:00
// Character x
2015-01-24 16:23:30 +08:00
tmp = strstr ( tmp , " x= " ) + 2 ;
2016-10-17 13:53:54 +08:00
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 ;
2016-10-17 13:53:54 +08:00
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 ;
2016-10-17 13:53:54 +08:00
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 ;
2016-10-17 13:53:54 +08:00
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 ;
2016-10-17 13:53:54 +08:00
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 ;
2016-10-17 13:53:54 +08:00
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 ;
2016-10-17 13:53:54 +08:00
sscanf ( tmp , " %hd " , & characterDefinition . xAdvance ) ;
return charID ;
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
2017-02-06 16:41:52 +08:00
uint64_t key = ( ( uint64_t ) first < < 32 ) | ( ( uint64_t ) second & 0xffffffffll ) ;
2016-10-17 13:53:54 +08:00
_kerningDictionary [ key ] = amount ;
2014-02-20 22:33:52 +08:00
}
2020-01-06 09:35:52 +08:00
FontFNT * FontFNT : : create ( const std : : string & fntFilePath , const Rect & imageRect , bool imageRotated )
2013-08-06 06:56:18 +08:00
{
2020-01-06 09:35:52 +08:00
const auto newConf = FNTConfigLoadFile ( fntFilePath ) ;
2013-08-07 04:43:29 +08:00
if ( ! newConf )
return nullptr ;
2020-01-06 09:35:52 +08:00
const auto tempFont = new FontFNT ( newConf , imageRect , imageRotated ) ;
if ( ! tempFont )
{
return nullptr ;
}
tempFont - > setFontSize ( ( float ) newConf - > _fontSize ) ;
tempFont - > autorelease ( ) ;
return tempFont ;
}
FontFNT * FontFNT : : create ( const std : : string & fntFilePath , const std : : string & subTextureKey )
{
const auto newConf = FNTConfigLoadFile ( fntFilePath ) ;
if ( ! newConf )
return nullptr ;
const auto frame = SpriteFrameCache : : getInstance ( ) - > getSpriteFrameByName ( subTextureKey ) ;
if ( ! frame )
{
return nullptr ;
}
auto tempFont = new FontFNT ( newConf , frame - > getRectInPixels ( ) , frame - > isRotated ( ) ) ;
if ( ! tempFont )
{
return nullptr ;
}
tempFont - > setFontSize ( ( float ) newConf - > _fontSize ) ;
tempFont - > autorelease ( ) ;
return tempFont ;
}
FontFNT * FontFNT : : create ( const std : : string & fntFilePath )
{
const auto newConf = FNTConfigLoadFile ( fntFilePath ) ;
if ( ! newConf )
return nullptr ;
2013-08-07 04:43:29 +08:00
// add the texture
2020-01-06 09:35:52 +08:00
const auto 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 ;
}
2020-01-06 09:35:52 +08:00
FontFNT * tempFont = new FontFNT ( newConf ) ;
2019-10-09 17:50:32 +08:00
tempFont - > setFontSize ( ( float ) 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
}
2020-01-06 09:35:52 +08:00
FontFNT * FontFNT : : create ( const std : : string & fntFilePath , const Vec2 & imageOffset )
{
return create ( fntFilePath , Rect ( imageOffset . x , imageOffset . y , 0 , 0 ) , false ) ;
}
FontFNT : : FontFNT ( BMFontConfiguration * theContfig , const Rect & imageRect , bool imageRotated )
: _configuration ( theContfig )
, _imageRectInPoints ( CC_RECT_PIXELS_TO_POINTS ( imageRect ) )
, _imageRotated ( imageRotated )
2014-02-20 22:33:52 +08:00
{
2015-01-08 10:22:45 +08:00
_configuration - > retain ( ) ;
2014-02-20 22:33:52 +08:00
}
2020-01-06 09:35:52 +08:00
FontFNT : : FontFNT ( BMFontConfiguration * theContfig )
: _configuration ( theContfig )
, _imageRectInPoints ( Rect : : ZERO )
, _imageRotated ( false )
{
}
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 ) ;
}
}
2017-02-06 16:41:52 +08:00
int * FontFNT : : getHorizontalKerningForTextUTF32 ( const std : : u32string & 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 )
2016-06-23 11:39:23 +08:00
return nullptr ;
2013-07-26 08:58:13 +08:00
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 )
2016-06-23 11:39:23 +08:00
return nullptr ;
2013-07-26 08:58:13 +08:00
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
}
2017-02-06 16:41:52 +08:00
int FontFNT : : getHorizontalKerningForChars ( char32_t firstChar , char32_t secondChar ) const
2013-07-26 08:58:13 +08:00
{
int ret = 0 ;
2017-02-06 16:41:52 +08:00
uint64_t key = ( ( uint64_t ) firstChar < < 32 ) | ( ( uint64_t ) secondChar & 0xffffffffll ) ;
2016-10-17 13:53:54 +08:00
auto iter = _configuration - > _kerningDictionary . find ( key ) ;
2013-07-26 08:58:13 +08:00
2016-10-17 13:53:54 +08:00
if ( iter ! = _configuration - > _kerningDictionary . end ( ) )
2013-07-26 08:58:13 +08:00
{
2016-10-17 13:53:54 +08:00
ret = iter - > second ;
2013-07-26 08:58:13 +08:00
}
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-10-17 13:53:54 +08:00
if ( _configuration - > _fontDefDictionary . empty ( ) )
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 ;
2019-10-09 17:50:32 +08:00
float originalLineHeight = ( float ) _configuration - > _commonHeight ;
2015-11-19 16:06:13 +08:00
float factor = 0.0f ;
2016-07-12 03:13:56 +08:00
if ( std : : abs ( _fontSize - originalFontSize ) < FLT_EPSILON ) {
2015-11-19 16:06:13 +08:00
factor = 1.0f ;
} else {
factor = _fontSize / originalFontSize ;
}
tempAtlas - > setLineHeight ( originalLineHeight * factor ) ;
2020-01-06 09:35:52 +08:00
auto rw = _imageRectInPoints . size . width ;
auto rh = _imageRectInPoints . size . height ;
if ( _imageRotated )
std : : swap ( rw , rh ) ;
const auto left = _imageRectInPoints . origin . x ;
const auto right = _imageRectInPoints . origin . x + rw ;
const auto top = _imageRectInPoints . origin . y ;
2016-10-17 13:53:54 +08:00
for ( auto & & e : _configuration - > _fontDefDictionary )
2013-08-02 05:36:34 +08:00
{
2016-10-17 13:53:54 +08:00
BMFontDef & fontDef = e . second ;
2020-01-06 09:35:52 +08:00
2013-08-02 05:36:34 +08:00
FontLetterDefinition tempDefinition ;
2016-10-17 13:53:54 +08:00
2020-01-06 09:35:52 +08:00
const auto tempRect = CC_RECT_PIXELS_TO_POINTS ( fontDef . rect ) ;
2013-08-02 05:36:34 +08:00
tempDefinition . offsetX = fontDef . xOffset ;
tempDefinition . offsetY = fontDef . yOffset ;
2020-01-06 09:35:52 +08:00
if ( _imageRotated )
{
tempDefinition . U = right - tempRect . origin . y - tempRect . size . height ;
tempDefinition . V = tempRect . origin . x + top ;
}
else
{
tempDefinition . U = tempRect . origin . x + left ;
tempDefinition . V = tempRect . origin . y + top ;
}
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 ;
2020-01-06 09:35:52 +08:00
tempDefinition . rotated = _imageRotated ;
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 ) ;
}
2020-01-06 09:35:52 +08:00
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