From b0e6b5a43f88765937168268c60fdd5b89a95e29 Mon Sep 17 00:00:00 2001 From: "Roman \"SBKarr" Date: Fri, 27 Dec 2013 22:29:59 +0400 Subject: [PATCH 1/2] AngelCode binary file format support for LabelBMFont --- cocos/2d/CCLabelBMFont.cpp | 175 ++++++++++++++++++++++++++++++++++++- cocos/2d/CCLabelBMFont.h | 1 + 2 files changed, 172 insertions(+), 4 deletions(-) diff --git a/cocos/2d/CCLabelBMFont.cpp b/cocos/2d/CCLabelBMFont.cpp index 7c2860fc2f..a19f7a3771 100644 --- a/cocos/2d/CCLabelBMFont.cpp +++ b/cocos/2d/CCLabelBMFont.cpp @@ -183,10 +183,16 @@ void CCBMFontConfiguration::purgeFontDefDictionary() std::set* CCBMFontConfiguration::parseConfigFile(const std::string& controlFile) { std::string fullpath = FileUtils::getInstance()->fullPathForFilename(controlFile); - - std::string contents = FileUtils::getInstance()->getStringFromFile(fullpath); - - CCASSERT(!contents.empty(), "CCBMFontConfiguration::parseConfigFile | Open file error."); + + Data data = FileUtils::getInstance()->getDataFromFile(fullpath); + CCASSERT((!data.isNull() && data.getSize() > 0), "CCBMFontConfiguration::parseConfigFile | Open file error."); + + if (memcmp("BMF", data.getBytes(), 3) == 0) { + std::set* ret = parseBinaryConfigFile(data.getBytes(), data.getSize(), controlFile); + return ret; + } + + std::string contents((const char*)data.getBytes()); std::set *validCharsString = new std::set(); @@ -260,6 +266,167 @@ std::set* CCBMFontConfiguration::parseConfigFile(const std::string return validCharsString; } +std::set* CCBMFontConfiguration::parseBinaryConfigFile(unsigned char* pData, unsigned long size, const std::string& controlFile) +{ + /* based on http://www.angelcode.com/products/bmfont/doc/file_format.html file format */ + + set *validCharsString = new set(); + + unsigned long remains = size; + + unsigned char version = pData[3]; + CCASSERT(version == 3, "Only version 3 is supported"); + + pData += 4; remains -= 4; + + while (remains > 0) + { + unsigned char blockId = pData[0]; pData += 1; remains -= 1; + uint32_t blockSize = 0; memcpy(&blockSize, pData, 4); + + pData += 4; remains -= 4; + + if (blockId == 1) + { + /* + fontSize 2 int 0 + bitField 1 bits 2 bit 0: smooth, bit 1: unicode, bit 2: italic, bit 3: bold, bit 4: fixedHeigth, bits 5-7: reserved + charSet 1 uint 3 + stretchH 2 uint 4 + aa 1 uint 6 + paddingUp 1 uint 7 + paddingRight 1 uint 8 + paddingDown 1 uint 9 + paddingLeft 1 uint 10 + spacingHoriz 1 uint 11 + spacingVert 1 uint 12 + outline 1 uint 13 added with version 2 + fontName n+1 string 14 null terminated string with length n + */ + + _padding.top = (unsigned char)pData[7]; + _padding.right = (unsigned char)pData[8]; + _padding.bottom = (unsigned char)pData[9]; + _padding.left = (unsigned char)pData[10]; + } + else if (blockId == 2) + { + /* + lineHeight 2 uint 0 + base 2 uint 2 + scaleW 2 uint 4 + scaleH 2 uint 6 + pages 2 uint 8 + bitField 1 bits 10 bits 0-6: reserved, bit 7: packed + alphaChnl 1 uint 11 + redChnl 1 uint 12 + greenChnl 1 uint 13 + blueChnl 1 uint 14 + */ + + uint16_t lineHeight = 0; memcpy(&lineHeight, pData, 2); + _commonHeight = lineHeight; + + uint16_t scaleW = 0; memcpy(&scaleW, pData + 4, 2); + uint16_t scaleH = 0; memcpy(&scaleH, pData + 6, 2); + + CCASSERT(scaleW <= Configuration::getInstance()->getMaxTextureSize() && scaleH <= Configuration::getInstance()->getMaxTextureSize(), "CCLabelBMFont: page can't be larger than supported"); + + uint16_t pages = 0; memcpy(&pages, pData + 8, 2); + CCASSERT(pages == 1, "CCBitfontAtlas: only supports 1 page"); + } + else if (blockId == 3) + { + /* + pageNames p*(n+1) strings 0 p null terminated strings, each with length n + */ + + const char *value = (const char *)pData; + size_t len = strlen(value); + CCASSERT(len < blockSize, "Block size should be less then string"); + + _atlasName = FileUtils::getInstance()->fullPathFromRelativeFile(value, controlFile); + } + else if (blockId == 4) + { + /* + id 4 uint 0+c*20 These fields are repeated until all characters have been described + x 2 uint 4+c*20 + y 2 uint 6+c*20 + width 2 uint 8+c*20 + height 2 uint 10+c*20 + xoffset 2 int 12+c*20 + yoffset 2 int 14+c*20 + xadvance 2 int 16+c*20 + page 1 uint 18+c*20 + chnl 1 uint 19+c*20 + */ + + unsigned long count = blockSize / 20; + + for (unsigned long i = 0; i < count; i++) + { + tFontDefHashElement* element = (tFontDefHashElement*)malloc( sizeof(*element) ); + + uint32_t charId = 0; memcpy(&charId, pData + (i * 20), 4); + element->fontDef.charID = charId; + + uint16_t charX = 0; memcpy(&charX, pData + (i * 20) + 4, 2); + element->fontDef.rect.origin.x = charX; + + uint16_t charY = 0; memcpy(&charY, pData + (i * 20) + 6, 2); + element->fontDef.rect.origin.y = charY; + + uint16_t charWidth = 0; memcpy(&charWidth, pData + (i * 20) + 8, 2); + element->fontDef.rect.size.width = charWidth; + + uint16_t charHeight = 0; memcpy(&charHeight, pData + (i * 20) + 10, 2); + element->fontDef.rect.size.height = charHeight; + + int16_t xoffset = 0; memcpy(&xoffset, pData + (i * 20) + 12, 2); + element->fontDef.xOffset = xoffset; + + int16_t yoffset = 0; memcpy(&yoffset, pData + (i * 20) + 14, 2); + element->fontDef.yOffset = yoffset; + + int16_t xadvance = 0; memcpy(&xadvance, pData + (i * 20) + 16, 2); + element->fontDef.xAdvance = xadvance; + + element->key = element->fontDef.charID; + HASH_ADD_INT(_fontDefDictionary, key, element); + + validCharsString->insert(element->fontDef.charID); + } + } + else if (blockId == 5) { + /* + first 4 uint 0+c*10 These fields are repeated until all kerning pairs have been described + second 4 uint 4+c*10 + amount 2 int 8+c*10 + */ + + unsigned long count = blockSize / 20; + + for (unsigned long i = 0; i < count; i++) + { + + uint32_t first = 0; memcpy(&first, pData + (i * 10), 4); + uint32_t second = 0; memcpy(&second, pData + (i * 10) + 4, 4); + int16_t amount = 0; memcpy(&amount, pData + (i * 10) + 8, 2); + + tKerningHashElement *element = (tKerningHashElement *)calloc( sizeof( *element ), 1 ); + element->amount = amount; + element->key = (first<<16) | (second&0xffff); + HASH_ADD_INT(_kerningDictionary,key, element); + } + } + + pData += blockSize; remains -= blockSize; + } + + return validCharsString; +} + void CCBMFontConfiguration::parseImageFileName(std::string line, const std::string& fntFile) { ////////////////////////////////////////////////////////////////////////// diff --git a/cocos/2d/CCLabelBMFont.h b/cocos/2d/CCLabelBMFont.h index 928d089370..9b3f226806 100644 --- a/cocos/2d/CCLabelBMFont.h +++ b/cocos/2d/CCLabelBMFont.h @@ -151,6 +151,7 @@ public: std::set* getCharacterSet() const; private: std::set* parseConfigFile(const std::string& controlFile); + std::set* parseBinaryConfigFile(unsigned char* pData, unsigned long size, const std::string& controlFile); void parseCharacterDefinition(std::string line, ccBMFontDef *characterDefinition); void parseInfoArguments(std::string line); void parseCommonArguments(std::string line); From 93f6d9c4f5bed89e25f6f003c57e66c72a66e6e5 Mon Sep 17 00:00:00 2001 From: "Roman \"SBKarr" Date: Sat, 28 Dec 2013 23:00:07 +0400 Subject: [PATCH 2/2] Added test case for binary fnt file Also, fixed nul-termination issue in file parsing --- cocos/2d/CCLabelBMFont.cpp | 2 +- .../TestCpp/Classes/LabelTest/LabelTest.cpp | 24 +++++++++++++++++++ .../Cpp/TestCpp/Classes/LabelTest/LabelTest.h | 11 +++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/cocos/2d/CCLabelBMFont.cpp b/cocos/2d/CCLabelBMFont.cpp index a19f7a3771..d3008ba72a 100644 --- a/cocos/2d/CCLabelBMFont.cpp +++ b/cocos/2d/CCLabelBMFont.cpp @@ -192,7 +192,7 @@ std::set* CCBMFontConfiguration::parseConfigFile(const std::string return ret; } - std::string contents((const char*)data.getBytes()); + std::string contents((const char*)data.getBytes(), data.getSize()); std::set *validCharsString = new std::set(); diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.cpp b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.cpp index 09280e9b63..8cb7da07be 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.cpp +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.cpp @@ -74,6 +74,7 @@ static std::function createFunctions[] = // should be moved to another test CL(Atlas1), CL(LabelBMFontCrashTest), + CL(LabelBMFontBinaryFormat), }; #define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0])) @@ -1669,3 +1670,26 @@ std::string LabelBMFontCrashTest::subtitle() const { return "Should not crash."; } + +// LabelBMFontBinaryFormat +LabelBMFontBinaryFormat::LabelBMFontBinaryFormat() +{ + auto s = Director::getInstance()->getWinSize(); + + auto bmFont = LabelBMFont::create(); + + bmFont->setFntFile("fonts/Roboto.bmf.fnt"); + bmFont->setString("It is working!"); + this->addChild(bmFont); + bmFont->setPosition(Point(s.width/2,s.height/4*2)); +} + +std::string LabelBMFontBinaryFormat::title() const +{ + return "LabelBMFont Binary FNT File"; +} + +std::string LabelBMFontBinaryFormat::subtitle() const +{ + return "This label uses font file in AngelCode binary format"; +} diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.h b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.h index 11c9934f93..6d19f97d6b 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.h +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.h @@ -429,6 +429,17 @@ public: virtual std::string subtitle() const override; }; +class LabelBMFontBinaryFormat : public AtlasDemo +{ +public: + CREATE_FUNC(LabelBMFontBinaryFormat); + + LabelBMFontBinaryFormat(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; +}; + // we don't support linebreak mode