├── Classes ├── AppDelegate.cpp ├── AppDelegate.h ├── FontCreator.cpp └── FontCreator.h ├── README.md └── Resources ├── ShadowFont.txt ├── StockFont.txt └── sampleFontDefines.plist /Classes/AppDelegate.cpp: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "FontCreator.h" 3 | 4 | USING_NS_CC; 5 | 6 | AppDelegate::AppDelegate() { 7 | 8 | } 9 | 10 | AppDelegate::~AppDelegate() 11 | { 12 | } 13 | 14 | //if you want a different context,just modify the value of glContextAttrs 15 | //it will takes effect on all platforms 16 | void AppDelegate::initGLContextAttrs() 17 | { 18 | //set OpenGL context attributions,now can only set six attributions: 19 | //red,green,blue,alpha,depth,stencil 20 | GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8}; 21 | 22 | GLView::setGLContextAttrs(glContextAttrs); 23 | } 24 | 25 | bool AppDelegate::applicationDidFinishLaunching() { 26 | // initialize director 27 | auto director = Director::getInstance(); 28 | auto glview = director->getOpenGLView(); 29 | if(!glview) { 30 | glview = GLViewImpl::create("Font Creator"); 31 | director->setOpenGLView(glview); 32 | } 33 | 34 | // turn on display FPS 35 | director->setDisplayStats(true); 36 | 37 | // set FPS. the default value is 1.0/60 if you don't call this 38 | director->setAnimationInterval(1.0 / 60); 39 | 40 | // create a scene. it's an autorelease object 41 | auto scene = Scene::create(); 42 | scene->addChild(game::tools::createFontCreator()); 43 | 44 | // run 45 | director->runWithScene(scene); 46 | 47 | return true; 48 | } 49 | 50 | // This function will be called when the app is inactive. When comes a phone call,it's be invoked too 51 | void AppDelegate::applicationDidEnterBackground() { 52 | Director::getInstance()->stopAnimation(); 53 | 54 | // if you use SimpleAudioEngine, it must be pause 55 | // SimpleAudioEngine::getInstance()->pauseBackgroundMusic(); 56 | } 57 | 58 | // this function will be called when the app is active again 59 | void AppDelegate::applicationWillEnterForeground() { 60 | Director::getInstance()->startAnimation(); 61 | 62 | // if you use SimpleAudioEngine, it must resume here 63 | // SimpleAudioEngine::getInstance()->resumeBackgroundMusic(); 64 | } 65 | -------------------------------------------------------------------------------- /Classes/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #ifndef _APP_DELEGATE_H_ 2 | #define _APP_DELEGATE_H_ 3 | 4 | #include "cocos2d.h" 5 | 6 | /** 7 | @brief The cocos2d Application. 8 | 9 | The reason for implement as private inheritance is to hide some interface call by Director. 10 | */ 11 | class AppDelegate : private cocos2d::Application 12 | { 13 | public: 14 | AppDelegate(); 15 | virtual ~AppDelegate(); 16 | 17 | virtual void initGLContextAttrs(); 18 | 19 | /** 20 | @brief Implement Director and Scene init code here. 21 | @return true Initialize success, app continue. 22 | @return false Initialize failed, app terminate. 23 | */ 24 | virtual bool applicationDidFinishLaunching(); 25 | 26 | /** 27 | @brief The function be called when the application enter background 28 | @param the pointer of the application 29 | */ 30 | virtual void applicationDidEnterBackground(); 31 | 32 | /** 33 | @brief The function be called when the application enter foreground 34 | @param the pointer of the application 35 | */ 36 | virtual void applicationWillEnterForeground(); 37 | }; 38 | 39 | #endif // _APP_DELEGATE_H_ 40 | 41 | -------------------------------------------------------------------------------- /Classes/FontCreator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // FontCreator.cpp 3 | // FontCreatorCpp 4 | // 5 | // Created by yedawei on 1/6/15. 6 | // 7 | // 8 | 9 | #include "FontCreator.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | namespace game { 15 | namespace tools { 16 | USING_NS_CC; 17 | using namespace std; 18 | 19 | // copy from http://www.cnblogs.com/mrblue/p/3407654.html 20 | static std::list split_utf8_string(const std::string& text) 21 | { 22 | std::list temp; 23 | do 24 | { 25 | if (text.length() <= 0) 26 | break; 27 | std::string::const_iterator begin = text.begin(); 28 | std::string::const_iterator end = text.end(); 29 | while (begin != end) 30 | { 31 | unsigned char c = *begin; 32 | int n = 0; 33 | if ((c & 0x80) == 0) 34 | n = 1; 35 | else if ((c & 0xE0) == 0xC0) 36 | n = 2; 37 | else if ((c & 0xF0) == 0xE0) 38 | n = 3; 39 | else if ((c & 0xF8) == 0xF0) 40 | n = 4; 41 | else if ((c & 0xFC) == 0xF8) 42 | n = 5; 43 | else if ((c & 0xFE) == 0xFC) 44 | n = 6; 45 | else 46 | break; 47 | if (end - begin < n) 48 | break; 49 | std::string substring; 50 | substring += *begin; 51 | bool isError = false; 52 | for (int i=1; i chars; 90 | FNTStruct() 91 | : chars() 92 | , layer(nullptr) 93 | { 94 | 95 | } 96 | } ; 97 | 98 | static Size sizeOfFontDef(const FontDefinition & def) { 99 | auto label = LabelTTF::createWithFontDefinition("建", const_cast(def)); 100 | Size sz = label->getContentSize(); 101 | return sz; 102 | } 103 | 104 | static int trim(int value) { 105 | for (int i = 1; i < 32; i ++) { 106 | int v = 1 << i; 107 | if (value < v) { 108 | return v; 109 | } 110 | } 111 | return 1; 112 | } 113 | 114 | static int sqr(int value) { 115 | int r = (int)sqrtf(value); 116 | return trim(r); 117 | } 118 | 119 | static FNTStruct createFNTStruct(const std::string & text, const FontDefinition & def) { 120 | std::list l = split_utf8_string(text); 121 | std::set s(l.begin(), l.end()); 122 | 123 | Size sz = sizeOfFontDef(def); 124 | int maxWidth = s.size() * sz.width; 125 | int minW = sqr(maxWidth * sz.height); 126 | 127 | int x = 0; 128 | int y = 0; 129 | 130 | Layer * layer = Layer::create(); 131 | layer->setAnchorPoint(Vec2(0, 0)); 132 | layer->ignoreAnchorPointForPosition(false); 133 | layer->setContentSize(Size(1024, 1024)); 134 | FNTStruct fnt; 135 | fnt.fontName = def._fontName; 136 | fnt.size = def._fontSize; 137 | fnt.lineHeight = sz.height; 138 | int lineMaxHeight = 0; 139 | auto nextLine = [&]() { 140 | x = 0; 141 | y = y + lineMaxHeight + 2; 142 | lineMaxHeight = 0; 143 | }; 144 | 145 | for (auto c : s) { 146 | auto label = LabelTTF::createWithFontDefinition(c, const_cast(def)); 147 | Size csz = label->getContentSize(); 148 | if (x + csz.width > minW) { 149 | nextLine(); 150 | } 151 | if (csz.height > lineMaxHeight) { 152 | lineMaxHeight = csz.height; 153 | } 154 | label->setPosition(x, y); 155 | label->setAnchorPoint(Vec2(0, 0)); 156 | layer->addChild(label); 157 | CharInfo info; 158 | info.c = c; 159 | info.x = x; 160 | info.y = y; 161 | info.width = csz.width; 162 | info.height = csz.height; 163 | info.xoffset = 0; 164 | info.yoffset = 0; 165 | info.xadvance = csz.width; 166 | if (def._shadow._shadowEnabled) { 167 | if (def._shadow._shadowOffset.width < 0) { 168 | info.xoffset = -def._shadow._shadowOffset.width; 169 | } 170 | info.xadvance = info.xadvance - fabs(def._shadow._shadowOffset.width); 171 | if (def._shadow._shadowOffset.height > 0) { 172 | info.yoffset = def._shadow._shadowOffset.height; 173 | } 174 | } 175 | if (def._stroke._strokeEnabled) { 176 | info.xoffset = info.xoffset + (int)def._stroke._strokeSize; 177 | info.xadvance = info.xadvance - (int)def._stroke._strokeSize; 178 | } 179 | info.page = 0; 180 | info.chnl = 0; 181 | fnt.chars.push_back(info); 182 | x = x + csz.width + 2; 183 | if (x > minW) { 184 | nextLine(); 185 | } 186 | } 187 | int lwidth = minW; 188 | int lheight = 0; 189 | if (x == 0) { 190 | lheight = y - 2; 191 | } else { 192 | lheight = y + lineMaxHeight; 193 | } 194 | lheight = trim(lheight); 195 | layer->setContentSize(Size(lwidth, lheight)); 196 | fnt.layer = layer; 197 | return fnt; 198 | } 199 | 200 | static void writeToFile(const string & name, const FNTStruct & fnt) { 201 | string path = FileUtils::getInstance()->getWritablePath() + name; 202 | CCLOG("writeTo: %s%s", path.c_str(), ".fnt"); 203 | Size sz = fnt.layer->getContentSize(); 204 | std::ofstream fs(path + ".fnt", std::ios::binary); 205 | fs << "info face=\"" << fnt.fontName << "\" size=" << fnt.size << " bold=0 italic=0 charset=\"\" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1\n"; 206 | fs << "common lineHeight=" << fnt.lineHeight << " base=26 scakeW=" << sz.width << " scaleH=" << sz.height << " pages=1 packed=0\n"; 207 | fs << "page id=0 file=\"" << name << ".png\"\n"; 208 | std::wstring_convert> utf8_conv; 209 | for (auto info : fnt.chars) { 210 | std::wstring ws = utf8_conv.from_bytes(info.c); 211 | fs << "char id=" << ((int)ws.at(0)) << " x=" << info.x << " y="<< (sz.height - info.y - info.height) << " width="<release(); 225 | } 226 | 227 | static int asInt(const ValueMap& vm, string key) { 228 | ValueMap::const_iterator it = vm.find(key); 229 | if (it != vm.end()) { 230 | return (*it).second.asInt(); 231 | } else { 232 | return 0; 233 | } 234 | } 235 | 236 | static string asString(const ValueMap& vm, string key) { 237 | ValueMap::const_iterator it = vm.find(key); 238 | if (it != vm.end()) { 239 | return (*it).second.asString(); 240 | } else { 241 | return string(""); 242 | } 243 | } 244 | 245 | static float asFloat(const ValueMap& vm, string key) { 246 | ValueMap::const_iterator it = vm.find(key); 247 | if (it != vm.end()) { 248 | return (*it).second.asFloat(); 249 | } else { 250 | return 0.0f; 251 | } 252 | } 253 | 254 | static bool asBool(const ValueMap& vm, string key) { 255 | ValueMap::const_iterator it = vm.find(key); 256 | if (it != vm.end()) { 257 | return (*it).second.asBool(); 258 | } else { 259 | return false; 260 | } 261 | } 262 | 263 | static Color3B asColor3B(const ValueMap& vm, string key) { 264 | ValueMap::const_iterator it = vm.find(key); 265 | if (it != vm.end()) { 266 | ValueMap cvm = (*it).second.asValueMap(); 267 | int r = asInt(cvm, "r"); 268 | int g = asInt(cvm, "g"); 269 | int b = asInt(cvm, "b"); 270 | return Color3B(r, g, b); 271 | } else { 272 | return Color3B::WHITE; 273 | } 274 | } 275 | 276 | static Size asSize(const ValueMap& vm, string key) { 277 | ValueMap::const_iterator it = vm.find(key); 278 | if (it != vm.end()) { 279 | ValueMap svm = (*it).second.asValueMap(); 280 | int width = asInt(svm, "width"); 281 | int height = asInt(svm, "height"); 282 | return Size(width, height); 283 | } else { 284 | return Size::ZERO; 285 | } 286 | } 287 | 288 | static FontDefinition FontDefinitionFromValueMap(const ValueMap& vm) { 289 | FontDefinition fontDef; 290 | fontDef._fontName = asString(vm, "fontName"); 291 | fontDef._fontSize = asInt(vm,"fontSize"); 292 | fontDef._fontFillColor = asColor3B(vm, "fontColor"); 293 | fontDef._shadow._shadowEnabled = asBool(vm,"shadowEnabled"); 294 | if (fontDef._shadow._shadowEnabled) { 295 | fontDef._shadow._shadowBlur = asFloat(vm,"shadowBlur"); 296 | fontDef._shadow._shadowOffset = asSize(vm, "shadowOffset"); 297 | fontDef._shadow._shadowOpacity = asFloat(vm,"shadowOpacity"); 298 | } 299 | fontDef._stroke._strokeEnabled = asBool(vm,"strokeEnabled"); 300 | if (fontDef._stroke._strokeEnabled) { 301 | fontDef._stroke._strokeSize = asInt(vm,"strokeSize"); 302 | fontDef._stroke._strokeColor = asColor3B(vm, "stockColor"); 303 | } 304 | return fontDef; 305 | } 306 | 307 | static string readAll(string & path) { 308 | std::ifstream t(path); 309 | return std::string((std::istreambuf_iterator(t)), 310 | std::istreambuf_iterator()); 311 | } 312 | 313 | void createFNTFiles(const string & configFile) { 314 | auto fileUtils = FileUtils::getInstance(); 315 | auto fontDefines = fileUtils->getValueVectorFromFile(configFile); 316 | for (auto value : fontDefines) { 317 | auto vm = value.asValueMap(); 318 | auto fontDef = FontDefinitionFromValueMap(vm); 319 | auto name = asString(vm, "name"); 320 | string path(fileUtils->fullPathForFilename(name + ".txt")); 321 | auto text = readAll(path); 322 | auto fnt = createFNTStruct(text, fontDef); 323 | writeToFile(name, fnt); 324 | } 325 | } 326 | 327 | Layer * createFontCreator() { 328 | createFNTFiles("sampleFontDefines.plist"); 329 | auto layer = Layer::create(); 330 | auto visibleSize = Director::getInstance()->getVisibleSize(); 331 | auto origin = Director::getInstance()->getVisibleOrigin(); 332 | auto colorLayer = LayerColor::create(Color4B(255, 255, 255, 255), visibleSize.width, visibleSize.height); 333 | layer->addChild(colorLayer); 334 | FontDefinition fontDef; 335 | fontDef._fontName = "Arial"; 336 | fontDef._fontSize = 100; 337 | fontDef._fontFillColor = Color3B(255, 0, 0); 338 | fontDef._shadow._shadowEnabled = true; 339 | fontDef._shadow._shadowBlur = 0.5; 340 | fontDef._shadow._shadowOffset = Size(4, 0); 341 | fontDef._shadow._shadowOpacity = 1.0f; 342 | fontDef._stroke._strokeEnabled = true; 343 | fontDef._stroke._strokeSize = 4; 344 | fontDef._stroke._strokeColor = Color3B(0, 0, 255); 345 | string text = "Task Complete"; 346 | auto label = LabelTTF::createWithFontDefinition(text, fontDef); 347 | label->setPosition(visibleSize.width/2, visibleSize.height/2); 348 | layer->addChild(label); 349 | return layer; 350 | } 351 | 352 | }; 353 | 354 | }; -------------------------------------------------------------------------------- /Classes/FontCreator.h: -------------------------------------------------------------------------------- 1 | // 2 | // FontCreator.h 3 | // FontCreatorCpp 4 | // 5 | // Created by yedawei on 1/6/15. 6 | // 7 | // 8 | 9 | #ifndef __FontCreatorCpp__FontCreator__ 10 | #define __FontCreatorCpp__FontCreator__ 11 | #include "cocos2d.h" 12 | namespace game { 13 | namespace tools { 14 | void createFNTFiles(const std::string & configFile); 15 | cocos2d::Layer * createFontCreator(); 16 | }; 17 | }; 18 | #endif /* defined(__FontCreatorCpp__FontCreator__) */ 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [Chinese] 2 | 从 plist 里面读取配置,生成fnt格式的字体文件. 3 | cocos2d-x 版本是3.3 4 | 5 | [English] 6 | Read config from .plist file, generate .fnt format font file. 7 | cocos2d-x version: 3.3 8 | 9 | 10 | -------------------------------------------------------------------------------- /Resources/ShadowFont.txt: -------------------------------------------------------------------------------- 1 | 你好helloworldabcdefghijklmnopqrstuvwxyz1234567890":L<>?{}+_)"建设银行 -------------------------------------------------------------------------------- /Resources/StockFont.txt: -------------------------------------------------------------------------------- 1 | 你好helloworldabcdefghijklmnopqrstuvwxyz1234567890":L<>?{}+_)"建设银行 -------------------------------------------------------------------------------- /Resources/sampleFontDefines.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | name 7 | ShadowFont 8 | fontName 9 | Arial 10 | fontSize 11 | 40 12 | fontColor 13 | 14 | r 15 | 255 16 | g 17 | 0 18 | b 19 | 255 20 | 21 | shadowEnabled 22 | 23 | shadowBlur 24 | 0.5 25 | shadowOffset 26 | 27 | width 28 | 5 29 | height 30 | 5 31 | 32 | shadowOpacity 33 | 0.5 34 | strokeEnabled 35 | 36 | strokeSize 37 | 3 38 | stockColor 39 | 40 | r 41 | 255 42 | g 43 | 0 44 | b 45 | 0 46 | 47 | 48 | 49 | name 50 | StockFont 51 | fontName 52 | Arial 53 | fontSize 54 | 40 55 | fontColor 56 | 57 | r 58 | 255 59 | g 60 | 0 61 | b 62 | 255 63 | 64 | shadowEnabled 65 | 66 | shadowBlur 67 | 0.5 68 | shadowOffset 69 | 70 | width 71 | 4 72 | height 73 | 4 74 | 75 | shadowOpacity 76 | 0.5 77 | strokeEnabled 78 | 79 | strokeSize 80 | 6 81 | stockColor 82 | 83 | r 84 | 255 85 | g 86 | 0 87 | b 88 | 0 89 | 90 | 91 | 92 | 93 | --------------------------------------------------------------------------------