font.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <pthread.h>
  6. #include <sys/sysinfo.h>
  7. // FontConfig
  8. #include "fcfg.h"
  9. // for sdf debugging
  10. #include "dumpImage.h"
  11. // #include "utilities.h"
  12. #include "font.h"
  13. // temp
  14. static void addFont(FontManager* fm, char* name);
  15. static FontGen* addChar(FontManager* fm, FT_Face* _ff, uint32_t code, int fontSize, char bold, char italic);
  16. static FT_Library ftLib = NULL;
  17. static void checkFTlib();
  18. static void checkFTlib() {
  19. FT_Error err;
  20. if(!ftLib) {
  21. err = FT_Init_FreeType(&ftLib);
  22. if(err) {
  23. fprintf(stderr, "Could not initialize FreeType library.\n");
  24. exit(1);
  25. }
  26. }
  27. }
  28. // super nifty site:
  29. // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
  30. static inline int nextPOT(int in) {
  31. in--;
  32. in |= in >> 1;
  33. in |= in >> 2;
  34. in |= in >> 4;
  35. in |= in >> 8;
  36. in |= in >> 16;
  37. in++;
  38. return in;
  39. }
  40. FontManager* FontManager_alloc() {
  41. FontManager* fm;
  42. fm = calloc(1, sizeof(*fm));
  43. FontManager_init(fm);
  44. return fm;
  45. }
  46. void FontManager_init(FontManager* fm) {
  47. FT_Error err;
  48. VEC_INIT(&fm->fonts);
  49. VEC_INIT(&fm->atlas);
  50. fm->oversample = 16;
  51. fm->maxAtlasSize = 512;
  52. checkFTlib();
  53. char* fontPath = "./unifont-11.0.03.ttf";
  54. err = FT_New_Face(ftLib, fontPath, 0, &fm->fallback);
  55. if(err) {
  56. fprintf(stderr, "Could not access fallback font at '%s'. (%x)\n", fontPath, (int)err);
  57. // exit(1);
  58. }
  59. // switch to unicode
  60. // all character code inputs are unicode codepoints
  61. FT_Select_Charmap(fm->fallback, FT_ENCODING_UNICODE);
  62. }
  63. // new font rendering info
  64. static char* defaultCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 `~!@#$%^&*()_+|-=\\{}[]:;<>?,./'\"";
  65. // 16.16 fixed point to float conversion
  66. static float f2f(uint32_t i) {
  67. return ((double)(i) / 65536.0);
  68. }
  69. // 26.6 fixed point to float conversion
  70. static float f2f26_6(uint32_t i) {
  71. return ((double)(i) / 64.0);
  72. }
  73. static void blit(
  74. int src_x, int src_y, int dst_x, int dst_y, int w, int h,
  75. int src_w, int dst_w, unsigned char* src, unsigned char* dst) {
  76. int y, x, s, d;
  77. // this may be upside down...
  78. for(y = 0; y < h; y++) {
  79. for(x = 0; x < w; x++) {
  80. s = ((y + src_y) * src_w) + src_x + x;
  81. d = ((y + dst_y) * dst_w) + dst_x + x;
  82. dst[d] = src[s];
  83. }
  84. }
  85. }
  86. static float dist(int a, int b) {
  87. return a*a + b*b;
  88. }
  89. static float dmin(int a, int b, float d) {
  90. return fmin(dist(a, b), d);
  91. }
  92. static int boundedOffset(int x, int y, int ox, int oy, int w, int h) {
  93. int x1 = x + ox;
  94. int y1 = y + oy;
  95. if(x1 < 0 || y1 < 0 || x1 >= w || y1 >= h) return -1;
  96. return x1 + (w * y1);
  97. }
  98. static uint8_t sdfEncode(float d, int inside, float maxDist) {
  99. int o;
  100. d = sqrt(d);
  101. float norm = d / maxDist;
  102. if(inside) norm = -norm;
  103. o = (norm * 192) + 64;
  104. return o < 0 ? 0 : (o > 255 ? 255 : o);
  105. }
  106. void CalcSDF_Software_(FontGen* fg) {
  107. int searchSize;
  108. int x, y, ox, oy, sx, sy;
  109. int dw, dh;
  110. uint8_t* input;
  111. uint8_t* output;
  112. float d, maxDist;
  113. searchSize = fg->oversample * fg->magnitude;
  114. maxDist = 0.5 * searchSize;
  115. dw = fg->rawGlyphSize.x;
  116. dh = fg->rawGlyphSize.y;
  117. // this is wrong
  118. fg->sdfGlyphSize.x = floor(((float)(dw/* + (2*fg->magnitude)*/) / (float)(fg->oversample)) + .5);
  119. fg->sdfGlyphSize.y = floor(((float)(dh/* + (2*fg->magnitude)*/) / (float)(fg->oversample)) + .5);
  120. fg->sdfGlyph = output = malloc(fg->sdfGlyphSize.x * fg->sdfGlyphSize.y * sizeof(uint8_t));
  121. input = fg->rawGlyph;
  122. fg->sdfBounds.min.x = 0;
  123. fg->sdfBounds.max.y = fg->sdfGlyphSize.y;
  124. fg->sdfBounds.max.x = fg->sdfGlyphSize.x;
  125. fg->sdfBounds.min.y = 0;
  126. // calculate the sdf
  127. for(y = 0; y < fg->sdfGlyphSize.y; y++) {
  128. for(x = 0; x < fg->sdfGlyphSize.x; x++) {
  129. int sx = x * fg->oversample;
  130. int sy = y * fg->oversample;
  131. //printf(".");
  132. // value right under the center of the pixel, to determine if we are inside
  133. // or outside the glyph
  134. int v = input[sx + (sy * dw)];
  135. d = 999999.99999;
  136. for(oy = -searchSize / 2; oy < searchSize; oy++) {
  137. for(ox = -searchSize / 2; ox < searchSize; ox++) {
  138. int off = boundedOffset(sx, sy, ox, oy, dw, dh);
  139. if(off >= 0 && input[off] != v)
  140. d = dmin(ox, oy, d);
  141. }
  142. }
  143. int q = sdfEncode(d, v, maxDist);
  144. //printf("%d,%d = %d (%f)\n",x,y,q,d);
  145. output[x + (y * fg->sdfGlyphSize.x)] = q;
  146. }
  147. }
  148. if(fg->sdfGlyphSize.x <= 0 || fg->sdfGlyphSize.y <= 0) {
  149. printf("broken glyph: %s-%d #%d\n", fg->font->name, fg->font->size, fg->code);
  150. }
  151. // find the bounds of the sdf data
  152. // first rows
  153. for(y = 0; y < fg->sdfGlyphSize.y; y++) {
  154. int hasData = 0;
  155. for(x = 0; x < fg->sdfGlyphSize.x; x++) {
  156. hasData += output[x + (y * fg->sdfGlyphSize.x)];
  157. }
  158. if(hasData / fg->sdfGlyphSize.x < 255) {
  159. fg->sdfBounds.min.y = y;
  160. break;
  161. }
  162. }
  163. for(y = fg->sdfGlyphSize.y - 1; y >= 0; y--) {
  164. int hasData = 0;
  165. for(x = 0; x < fg->sdfGlyphSize.x; x++) {
  166. hasData += output[x + (y * fg->sdfGlyphSize.x)];
  167. }
  168. if(hasData / fg->sdfGlyphSize.x < 255) {
  169. fg->sdfBounds.max.y = y + 1;
  170. break;
  171. }
  172. }
  173. for(x = 0; x < fg->sdfGlyphSize.x; x++) {
  174. int hasData = 0;
  175. for(y = 0; y < fg->sdfGlyphSize.y; y++) {
  176. hasData += output[x + (y * fg->sdfGlyphSize.x)];
  177. }
  178. if(hasData / fg->sdfGlyphSize.y < 255) {
  179. fg->sdfBounds.min.x = x;
  180. break;
  181. }
  182. }
  183. for(x = fg->sdfGlyphSize.x - 1; x >= 0; x++) {
  184. int hasData = 0;
  185. for(y = 0; y < fg->sdfGlyphSize.y; y++) {
  186. hasData += output[x + (y * fg->sdfGlyphSize.x)];
  187. }
  188. if(hasData / fg->sdfGlyphSize.y < 255) {
  189. fg->sdfBounds.max.x = x + 1;
  190. break;
  191. }
  192. }
  193. fg->sdfDataSize.x = fg->sdfBounds.max.x - fg->sdfBounds.min.x;
  194. fg->sdfDataSize.y = fg->sdfBounds.max.y - fg->sdfBounds.min.y;
  195. free(fg->rawGlyph);
  196. }
  197. static FontGen* addChar(FontManager* fm, FT_Face* _ff, uint32_t code, int fontSize, char bold, char italic) {
  198. FontGen* fg;
  199. FT_Error err;
  200. FT_GlyphSlot slot;
  201. FT_Face* ff;
  202. fg = calloc(1, sizeof(*fg));
  203. fg->code = code;
  204. fg->italic = italic;
  205. fg->bold = bold;
  206. fg->oversample = fm->oversample;
  207. fg->magnitude = fm->magnitude;
  208. int rawSize = fontSize * fm->oversample;
  209. if(0 != FT_Get_Char_Index(*_ff, code)) {
  210. ff = _ff;
  211. }
  212. else if(0 != FT_Get_Char_Index(fm->fallback, code)) {
  213. ff = &fm->fallback;
  214. }
  215. else {
  216. // the character is missing.
  217. return NULL;
  218. }
  219. err = FT_Set_Pixel_Sizes(*ff, 0, rawSize);
  220. if(err) {
  221. fprintf(stderr, "Could not set pixel size to %dpx.\n", rawSize);
  222. free(fg);
  223. exit(1);
  224. }
  225. err = FT_Load_Char(*ff, code, FT_LOAD_DEFAULT | FT_LOAD_MONOCHROME);
  226. //f2f(slot->metrics.horiBearingY);
  227. // draw character to freetype's internal buffer and copy it here
  228. FT_Load_Char(*ff, code, FT_LOAD_RENDER);
  229. // slot is a pointer
  230. slot = (*ff)->glyph;
  231. // typographic metrics for later. has nothing to do with sdf generation
  232. fg->rawAdvance = f2f(slot->linearHoriAdvance);
  233. fg->rawBearing.x = f2f26_6(slot->metrics.horiBearingX);
  234. fg->rawBearing.y = f2f26_6(slot->metrics.horiBearingY);
  235. // back to sdf generation
  236. Vector2i rawImgSz = {(slot->metrics.width >> 6), (slot->metrics.height >> 6)};
  237. fg->rawGlyphSize.x = (slot->metrics.width >> 6) + (fg->oversample * fg->magnitude);
  238. fg->rawGlyphSize.y = (slot->metrics.height >> 6) + (fg->oversample * fg->magnitude);
  239. // the raw glyph is copied to the middle of a larger buffer to make the sdf algorithm simpler
  240. fg->rawGlyph = calloc(1, sizeof(*fg->rawGlyph) * fg->rawGlyphSize.x * fg->rawGlyphSize.y);
  241. blit(
  242. 0, 0, // src x and y offset for the image
  243. (fg->oversample * fg->magnitude * .5), (fg->oversample * fg->magnitude * .5), // dst offset
  244. rawImgSz.x, rawImgSz.y, // width and height
  245. slot->bitmap.pitch, fg->rawGlyphSize.x, // src and dst row widths
  246. slot->bitmap.buffer, // source
  247. fg->rawGlyph); // destination
  248. return fg;
  249. }
  250. void* sdf_thread(void* _fm) {
  251. FontManager* fm = (FontManager*)_fm;
  252. int i = 0;
  253. while(1) {
  254. i = atomic_fetch_add(&fm->genCounter, 1);
  255. if(i >= VEC_LEN(&fm->gen)) break;
  256. FontGen* fg = VEC_ITEM(&fm->gen, i);
  257. if(fm->verbose >= 0) printf("calc: '%s':%d:%d %c\n", fg->font->name, fg->bold, fg->italic, fg->code);
  258. CalcSDF_Software_(fg);
  259. }
  260. pthread_exit(NULL);
  261. }
  262. void FontManager_finalize(FontManager* fm) {
  263. int maxThreads = MIN(get_nprocs(), fm->maxThreads);
  264. pthread_t threads[maxThreads];
  265. for(int i = 0; i < maxThreads; i++) {
  266. int ret = pthread_create(&threads[i], NULL, sdf_thread, fm);
  267. if(ret) {
  268. printf("failed to spawn thread in FontManager\n");
  269. exit(1);
  270. }
  271. }
  272. // wait for the work to get done
  273. for(int i = 0; i < maxThreads; i++) {
  274. pthread_join(threads[i], NULL);
  275. }
  276. }
  277. // sorting function for fontgen array
  278. static int gen_comp(const void* aa, const void * bb) {
  279. FontGen* a = *((FontGen**)aa);
  280. FontGen* b = *((FontGen**)bb);
  281. if(a->sdfDataSize.y == b->sdfDataSize.y) {
  282. return b->sdfDataSize.x - a->sdfDataSize.x;
  283. }
  284. else {
  285. return b->sdfDataSize.y - a->sdfDataSize.y;
  286. }
  287. }
  288. GUIFont* GUIFont_alloc(char* name) {
  289. GUIFont* f;
  290. f = calloc(1, sizeof(*f));
  291. f->name = strdup(name);
  292. f->charsLen = 128;
  293. f->regular = calloc(1, sizeof(*f->regular) * f->charsLen);
  294. f->bold = calloc(1, sizeof(*f->bold) * f->charsLen);
  295. f->italic= calloc(1, sizeof(*f->italic) * f->charsLen);
  296. f->boldItalic = calloc(1, sizeof(*f->boldItalic) * f->charsLen);
  297. return f;
  298. }
  299. void FontManager_addFont2(FontManager* fm, char* name, uint32_t* charset, int size, char bold, char italic) {
  300. GUIFont* f;
  301. FT_Error err;
  302. FT_Face fontFace;
  303. //defaultCharset = "I";
  304. int len = u32strlen(charset);
  305. int fontSize = size; // pixels
  306. checkFTlib();
  307. // TODO: load font
  308. char* fontPath = getFontFile2(name, bold, italic);
  309. if(!fontPath) {
  310. fprintf(stderr, "Could not load font '%s'\n", name);
  311. exit(1);
  312. }
  313. if(fm->verbose >= 0) printf("Font path: %s: %s\n", name, fontPath);
  314. err = FT_New_Face(ftLib, fontPath, 0, &fontFace);
  315. if(err) {
  316. fprintf(stderr, "Could not access font '%s' at '%s'.\n", name, fontPath);
  317. exit(1);
  318. }
  319. // switch to unicode
  320. // all character code inputs are unicode codepoints
  321. FT_Select_Charmap(fontFace, FT_ENCODING_UNICODE);
  322. // look for an existing matching font
  323. f = NULL;
  324. VEC_EACH(&fm->fonts, fi, fo) {
  325. if(size == fo->size && 0 == strcmp(fo->name, name)) {
  326. f = fo;
  327. break;
  328. }
  329. }
  330. if(f == NULL) {
  331. f = GUIFont_alloc(name);
  332. f->size = size;
  333. VEC_PUSH(&fm->fonts, f);
  334. }
  335. for(int i = 0; i < len; i++) {
  336. // printf("calc: '%s':%d:%d %c\n", name, bold, italic, charset[i]);
  337. FontGen* fg = addChar(fm, &fontFace, charset[i], fontSize, bold, italic);
  338. if(!fg) continue;
  339. fg->font = f;
  340. VEC_PUSH(&fm->gen, fg);
  341. }
  342. }
  343. void FontManager_createAtlas(FontManager* fm) {
  344. char buf[32];
  345. // order the characters by height then width, tallest and widest first.
  346. VEC_SORT(&fm->gen, gen_comp);
  347. int totalWidth = 0;
  348. VEC_EACH(&fm->gen, ind, gen) {
  349. //printf("%c: h: %d, w: %d \n", gen->code, gen->sdfDataSize.y, gen->sdfDataSize.x);
  350. totalWidth += gen->sdfDataSize.x;
  351. }
  352. int maxHeight = VEC_ITEM(&fm->gen, 0)->sdfDataSize.y;
  353. int naiveSize = ceil(sqrt(maxHeight * totalWidth));
  354. int pot = nextPOT(naiveSize);
  355. int pot2 = naiveSize / 2;
  356. //printf("naive min tex size: %d -> %d (%d)\n", naiveSize, pot, totalWidth);
  357. if(fm->maxAtlasSize > 0) {
  358. pot = MIN(pot, fm->maxAtlasSize);
  359. }
  360. // test the packing
  361. int row = 0;
  362. int hext = maxHeight;
  363. int rowWidth = 0;
  364. // copy the chars into the atlas, cleaning as we go
  365. uint8_t* texData = malloc(sizeof(*texData) * pot * pot);
  366. memset(texData, 255, sizeof(*texData) * pot * pot);
  367. fm->atlasSize = pot;
  368. row = 0;
  369. hext = 0;
  370. int prevhext = maxHeight;
  371. rowWidth = 0;
  372. VEC_EACH(&fm->gen, ind, gen) {
  373. if(rowWidth + gen->sdfDataSize.x > pot) {
  374. row++;
  375. rowWidth = 0;
  376. hext += prevhext;
  377. prevhext = gen->sdfDataSize.y;
  378. // next texture
  379. if(hext + prevhext > pot) {
  380. VEC_PUSH(&fm->atlas, texData);
  381. sprintf(buf, fm->pngFileFormat, (int)VEC_LEN(&fm->atlas));
  382. writePNG(buf, 1, texData, pot, pot);
  383. if(fm->verbose >= 0) printf("Saved atlas file '%s'\n", buf);
  384. texData = malloc(sizeof(*texData) * pot * pot);
  385. // make everything white, the "empty" value
  386. memset(texData, 255, sizeof(*texData) * pot * pot);
  387. hext = 0;
  388. }
  389. }
  390. // blit the sdf bitmap data
  391. blit(
  392. gen->sdfBounds.min.x, gen->sdfBounds.min.y, // src x and y offset for the image
  393. rowWidth, hext, // dst offset
  394. gen->sdfDataSize.x, gen->sdfDataSize.y, // width and height
  395. gen->sdfGlyphSize.x, pot, // src and dst row widths
  396. gen->sdfGlyph, // source
  397. texData); // destination
  398. // copy info over to font
  399. struct charInfo* c;
  400. if(gen->bold && gen->italic) {
  401. gen->font->hasBoldItalic |= 1;
  402. c = &gen->font->boldItalic[gen->code];
  403. }
  404. else if(gen->bold) {
  405. gen->font->hasBold |= 1;
  406. c = &gen->font->bold[gen->code];
  407. }
  408. else if(gen->italic) {
  409. gen->font->hasItalic |= 1;
  410. c = &gen->font->italic[gen->code];
  411. }
  412. else {
  413. gen->font->hasRegular |= 1;
  414. c = &gen->font->regular[gen->code];
  415. }
  416. c->code = gen->code;
  417. c->texIndex = VEC_LEN(&fm->atlas);
  418. c->texelOffset.x = rowWidth;
  419. c->texelOffset.y = hext;
  420. c->texelSize = gen->sdfDataSize;
  421. c->texNormOffset.x = (float)rowWidth / (float)pot;
  422. c->texNormOffset.y = (float)hext / (float)pot;
  423. c->texNormSize.x = (float)gen->sdfDataSize.x / (float)pot;
  424. c->texNormSize.y = (float)gen->sdfDataSize.y / (float)pot;
  425. // BUG: wrong? needs magnitude? used to be just oversample. looks like it needs to be both
  426. c->advance = gen->rawAdvance / (float)gen->magnitude / (float)gen->oversample;
  427. c->topLeftOffset.x = (gen->rawBearing.x / (float)gen->magnitude / (float)gen->oversample);// + (float)gen->sdfBounds.min.x;
  428. c->topLeftOffset.y = (gen->rawBearing.y / (float)gen->magnitude / (float)gen->oversample);// - (float)gen->sdfBounds.min.y;
  429. c->size.x = gen->sdfDataSize.x;
  430. c->size.y = gen->sdfDataSize.y;
  431. // printf("toff: %f, %f \n", c->texNormOffset.x, c->texNormOffset.y);
  432. // printf("tsize: %f, %f \n", c->texNormSize.x, c->texNormSize.y);
  433. // printf("ltoff: %f, %f \n", c->topLeftOffset.x, c->topLeftOffset.y);
  434. // advance the write offset
  435. rowWidth += gen->sdfDataSize.x;
  436. // clean up the FontGen struct
  437. free(gen->sdfGlyph);
  438. free(gen);
  439. }
  440. VEC_PUSH(&fm->atlas, texData);
  441. sprintf(buf, fm->pngFileFormat, (int)VEC_LEN(&fm->atlas));
  442. writePNG(buf, 1, texData, pot, pot);
  443. if(fm->verbose >= 0) printf("Saved atlas file '%s'\n", buf);
  444. VEC_FREE(&fm->gen);
  445. }
  446. void printCharinfo(FILE* f, char* prefix, struct charInfo* ci) {
  447. if(ci->code == 0) return;
  448. // fprintf(f, "%s%d: {\n", prefix, ci->code);
  449. // fprintf(f, "%s\tcode: %d,\n", prefix, ci->code);
  450. // fprintf(f, "%s\ttexIndex: %d,\n", prefix, ci->texIndex);
  451. // fprintf(f, "%s\ttexelOffset: [%d, %d],\n", prefix, ci->texelOffset.x, ci->texelOffset.y);
  452. // fprintf(f, "%s\ttexelSize: [%d, %d],\n", prefix, ci->texelSize.x, ci->texelSize.y);
  453. // fprintf(f, "%s\tnormalizedOffset: [%f, %f],\n", prefix, ci->texNormOffset.x, ci->texNormOffset.y);
  454. // fprintf(f, "%s\tnormalizedSize: [%f, %f],\n", prefix, ci->texNormSize.x, ci->texNormSize.y);
  455. // fprintf(f, "%s\tadvance: %f,\n", prefix, ci->advance);
  456. // fprintf(f, "%s\tboxOffset: [%f, %f],\n", prefix, ci->topLeftOffset.x, ci->topLeftOffset.y);
  457. // fprintf(f, "%s\tboxSize: [%f, %f]\n", prefix, ci->size.x, ci->size.y);
  458. // fprintf(f, "%s},\n", prefix);
  459. fprintf(f, "%s\"%d\": [ ", prefix, ci->code);
  460. fprintf(f, "%d, ", ci->code);
  461. fprintf(f, "%d, ", ci->texIndex);
  462. fprintf(f, "[%d, %d], ", ci->texelOffset.x, ci->texelOffset.y);
  463. fprintf(f, "[%d, %d], ", ci->texelSize.x, ci->texelSize.y);
  464. fprintf(f, "[%f, %f], ", ci->texNormOffset.x, ci->texNormOffset.y);
  465. fprintf(f, "[%f, %f], ", ci->texNormSize.x, ci->texNormSize.y);
  466. fprintf(f, "%f, ", ci->advance);
  467. fprintf(f, "[%f, %f], ", ci->topLeftOffset.x, ci->topLeftOffset.y);
  468. fprintf(f, "[%f, %f] ", ci->size.x, ci->size.y);
  469. fprintf(f, "],\n", prefix);
  470. }
  471. void FontManager_saveJSON(FontManager* fm, char* path) {
  472. FILE* f;
  473. f = fopen(path, "w");
  474. if(!f) {
  475. fprintf(stderr, "Could not save JSON metadata to '%s'\n", path);
  476. exit(1);
  477. }
  478. fprintf(f, "{\n");
  479. fprintf(f, "\t\"layers\": [\n");
  480. VEC_LOOP(&fm->atlas, fi) {
  481. fprintf(f, "\t\t\"");
  482. fprintf(f, fm->pngFileFormat, (int)fi);
  483. fprintf(f, "\",\n");
  484. }
  485. fprintf(f, "\t],\n");
  486. fprintf(f, "\t\"charInfoIndices\": {\n");
  487. fprintf(f, "\t\t\"code\": 0,\n");
  488. fprintf(f, "\t\t\"texIndex\": 1,\n");
  489. fprintf(f, "\t\t\"texelOffset\": 2,\n");
  490. fprintf(f, "\t\t\"texelSize\": 3,\n");
  491. fprintf(f, "\t\t\"normalizedOffset\": 4,\n");
  492. fprintf(f, "\t\t\"normalizedSize\": 5,\n");
  493. fprintf(f, "\t\t\"advance\": 6,\n");
  494. fprintf(f, "\t\t\"boxOffset\": 7,\n");
  495. fprintf(f, "\t\t\"boxSize\": 8\n");
  496. fprintf(f, "\t},\n");
  497. fprintf(f, "\t\"fonts\": {\n");
  498. VEC_EACH(&fm->fonts, fi, font) {
  499. fprintf(f, "\t\t\"%s-%d\": {\n", font->name, font->size);
  500. fprintf(f, "\t\t\t\"name\": \"%s\",\n", font->name);
  501. fprintf(f, "\t\t\t\"size\": %d,\n", font->size);
  502. if(font->hasRegular) {
  503. fprintf(f, "\t\t\t\"regular\": {\n");
  504. for(int i = 0; i < font->charsLen; i++) {
  505. printCharinfo(f, "\t\t\t\t", font->regular + i);
  506. }
  507. fprintf(f, "\t\t\t},\n");
  508. }
  509. if(font->hasBold) {
  510. fprintf(f, "\t\t\t\"bold\": {\n");
  511. for(int i = 0; i < font->charsLen; i++) {
  512. printCharinfo(f, "\t\t\t\t", &font->bold[i]);
  513. }
  514. fprintf(f, "\t\t\t},\n");
  515. }
  516. if(font->hasItalic) {
  517. fprintf(f, "\t\t\t\"italic\": {\n");
  518. for(int i = 0; i < font->charsLen; i++) {
  519. printCharinfo(f, "\t\t\t\t", &font->italic[i]);
  520. }
  521. fprintf(f, "\t\t\t},\n");
  522. }
  523. if(font->hasBoldItalic) {
  524. fprintf(f, "\t\t\t\"boldItalic\": {\n");
  525. for(int i = 0; i < font->charsLen; i++) {
  526. printCharinfo(f, "\t\t\t\t", &font->boldItalic[i]);
  527. }
  528. fprintf(f, "\t\t\t},\n");
  529. }
  530. fprintf(f, "\t\t},\n");
  531. }
  532. fprintf(f, "\t}\n");
  533. fprintf(f, "}");
  534. fclose(f);
  535. if(fm->verbose >= 0) printf("Saved config file '%s'\n", path);
  536. }