You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1727 lines
46KB

  1. //
  2. // Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. #ifndef FONS_H
  19. #define FONS_H
  20. #define FONS_INVALID -1
  21. enum FONSflags {
  22. FONS_ZERO_TOPLEFT = 1,
  23. FONS_ZERO_BOTTOMLEFT = 2,
  24. };
  25. enum FONSalign {
  26. // Horizontal align
  27. FONS_ALIGN_LEFT = 1<<0, // Default
  28. FONS_ALIGN_CENTER = 1<<1,
  29. FONS_ALIGN_RIGHT = 1<<2,
  30. // Vertical align
  31. FONS_ALIGN_TOP = 1<<3,
  32. FONS_ALIGN_MIDDLE = 1<<4,
  33. FONS_ALIGN_BOTTOM = 1<<5,
  34. FONS_ALIGN_BASELINE = 1<<6, // Default
  35. };
  36. enum FONSerrorCode {
  37. // Font atlas is full.
  38. FONS_ATLAS_FULL = 1,
  39. // Scratch memory used to render glyphs is full, requested size reported in 'val', you may need to bump up FONS_SCRATCH_BUF_SIZE.
  40. FONS_SCRATCH_FULL = 2,
  41. // Calls to fonsPushState has created too large stack, if you need deep state stack bump up FONS_MAX_STATES.
  42. FONS_STATES_OVERFLOW = 3,
  43. // Trying to pop too many states fonsPopState().
  44. FONS_STATES_UNDERFLOW = 4,
  45. };
  46. struct FONSparams {
  47. int width, height;
  48. unsigned char flags;
  49. void* userPtr;
  50. int (*renderCreate)(void* uptr, int width, int height);
  51. int (*renderResize)(void* uptr, int width, int height);
  52. void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data);
  53. void (*renderDraw)(void* uptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts);
  54. void (*renderDelete)(void* uptr);
  55. };
  56. typedef struct FONSparams FONSparams;
  57. struct FONSquad
  58. {
  59. float x0,y0,s0,t0;
  60. float x1,y1,s1,t1;
  61. };
  62. typedef struct FONSquad FONSquad;
  63. struct FONStextIter {
  64. float x, y, nextx, nexty, scale, spacing;
  65. unsigned int codepoint;
  66. short isize, iblur;
  67. struct FONSfont* font;
  68. int prevGlyphIndex;
  69. const char* str;
  70. const char* next;
  71. const char* end;
  72. unsigned int utf8state;
  73. };
  74. typedef struct FONStextIter FONStextIter;
  75. typedef struct FONScontext FONScontext;
  76. // Constructor and destructor.
  77. FONScontext* fonsCreateInternal(FONSparams* params);
  78. void fonsDeleteInternal(FONScontext* s);
  79. void fonsSetErrorCallback(FONScontext* s, void (*callback)(void* uptr, int error, int val), void* uptr);
  80. // Returns current atlas size.
  81. void fonsGetAtlasSize(FONScontext* s, int* width, int* height);
  82. // Expands the atlas size.
  83. int fonsExpandAtlas(FONScontext* s, int width, int height);
  84. // Resets the whole stash.
  85. int fonsResetAtlas(FONScontext* stash, int width, int height);
  86. // Add fonts
  87. int fonsAddFont(FONScontext* s, const char* name, const char* path);
  88. int fonsAddFontMem(FONScontext* s, const char* name, unsigned char* data, int ndata, int freeData);
  89. int fonsGetFontByName(FONScontext* s, const char* name);
  90. // State handling
  91. void fonsPushState(FONScontext* s);
  92. void fonsPopState(FONScontext* s);
  93. void fonsClearState(FONScontext* s);
  94. // State setting
  95. void fonsSetSize(FONScontext* s, float size);
  96. void fonsSetColor(FONScontext* s, unsigned int color);
  97. void fonsSetSpacing(FONScontext* s, float spacing);
  98. void fonsSetBlur(FONScontext* s, float blur);
  99. void fonsSetAlign(FONScontext* s, int align);
  100. void fonsSetFont(FONScontext* s, int font);
  101. // Draw text
  102. float fonsDrawText(FONScontext* s, float x, float y, const char* string, const char* end);
  103. // Measure text
  104. float fonsTextBounds(FONScontext* s, float x, float y, const char* string, const char* end, float* bounds);
  105. void fonsLineBounds(FONScontext* s, float y, float* miny, float* maxy);
  106. void fonsVertMetrics(FONScontext* s, float* ascender, float* descender, float* lineh);
  107. // Text iterator
  108. int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, float x, float y, const char* str, const char* end);
  109. int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, struct FONSquad* quad);
  110. // Pull texture changes
  111. const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height);
  112. int fonsValidateTexture(FONScontext* s, int* dirty);
  113. // Draws the stash texture for debugging
  114. void fonsDrawDebug(FONScontext* s, float x, float y);
  115. #endif // FONTSTASH_H
  116. #ifdef FONTSTASH_IMPLEMENTATION
  117. #define FONS_NOTUSED(v) (void)sizeof(v)
  118. #ifdef FONS_USE_FREETYPE
  119. #include <ft2build.h>
  120. #include FT_FREETYPE_H
  121. #include FT_ADVANCES_H
  122. #include <math.h>
  123. struct FONSttFontImpl {
  124. FT_Face font;
  125. };
  126. typedef struct FONSttFontImpl FONSttFontImpl;
  127. static FT_Library ftLibrary;
  128. int fons__tt_init(FONScontext *context)
  129. {
  130. FT_Error ftError;
  131. FONS_NOTUSED(context);
  132. ftError = FT_Init_FreeType(&ftLibrary);
  133. return ftError == 0;
  134. }
  135. int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize)
  136. {
  137. FT_Error ftError;
  138. FONS_NOTUSED(context);
  139. //font->font.userdata = stash;
  140. ftError = FT_New_Memory_Face(ftLibrary, (const FT_Byte*)data, dataSize, 0, &font->font);
  141. return ftError == 0;
  142. }
  143. void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap)
  144. {
  145. *ascent = font->font->ascender;
  146. *descent = font->font->descender;
  147. *lineGap = font->font->height - (*ascent - *descent);
  148. }
  149. float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
  150. {
  151. return size / (font->font->ascender - font->font->descender);
  152. }
  153. int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
  154. {
  155. return FT_Get_Char_Index(font->font, codepoint);
  156. }
  157. int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale,
  158. int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1)
  159. {
  160. FT_Error ftError;
  161. FT_GlyphSlot ftGlyph;
  162. FT_Fixed advFixed;
  163. FONS_NOTUSED(scale);
  164. ftError = FT_Set_Pixel_Sizes(font->font, 0, (FT_UInt)(size * (float)font->font->units_per_EM / (float)(font->font->ascender - font->font->descender)));
  165. if (ftError) return 0;
  166. ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER);
  167. if (ftError) return 0;
  168. ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, &advFixed);
  169. if (ftError) return 0;
  170. ftGlyph = font->font->glyph;
  171. *advance = (int)advFixed;
  172. *lsb = (int)ftGlyph->metrics.horiBearingX;
  173. *x0 = ftGlyph->bitmap_left;
  174. *x1 = *x0 + ftGlyph->bitmap.width;
  175. *y0 = -ftGlyph->bitmap_top;
  176. *y1 = *y0 + ftGlyph->bitmap.rows;
  177. return 1;
  178. }
  179. void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride,
  180. float scaleX, float scaleY, int glyph)
  181. {
  182. FT_GlyphSlot ftGlyph = font->font->glyph;
  183. int ftGlyphOffset = 0;
  184. int x, y;
  185. FONS_NOTUSED(outWidth);
  186. FONS_NOTUSED(outHeight);
  187. FONS_NOTUSED(scaleX);
  188. FONS_NOTUSED(scaleY);
  189. FONS_NOTUSED(glyph); // glyph has already been loaded by fons__tt_buildGlyphBitmap
  190. for ( y = 0; y < ftGlyph->bitmap.rows; y++ ) {
  191. for ( x = 0; x < ftGlyph->bitmap.width; x++ ) {
  192. output[(y * outStride) + x] = ftGlyph->bitmap.buffer[ftGlyphOffset++];
  193. }
  194. }
  195. }
  196. int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
  197. {
  198. FT_Vector ftKerning;
  199. FT_Get_Kerning(font->font, glyph1, glyph2, FT_KERNING_DEFAULT, &ftKerning);
  200. return (int)((ftKerning.x + 32) >> 6); // Round up and convert to integer
  201. }
  202. #else
  203. #define STB_TRUETYPE_IMPLEMENTATION
  204. static void* fons__tmpalloc(size_t size, void* up);
  205. static void fons__tmpfree(void* ptr, void* up);
  206. #define STBTT_malloc(x,u) fons__tmpalloc(x,u)
  207. #define STBTT_free(x,u) fons__tmpfree(x,u)
  208. #include "stb_truetype.h"
  209. struct FONSttFontImpl {
  210. stbtt_fontinfo font;
  211. };
  212. typedef struct FONSttFontImpl FONSttFontImpl;
  213. int fons__tt_init(FONScontext *context)
  214. {
  215. FONS_NOTUSED(context);
  216. return 1;
  217. }
  218. int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize)
  219. {
  220. int stbError;
  221. FONS_NOTUSED(dataSize);
  222. font->font.userdata = context;
  223. stbError = stbtt_InitFont(&font->font, data, 0);
  224. return stbError;
  225. }
  226. void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap)
  227. {
  228. stbtt_GetFontVMetrics(&font->font, ascent, descent, lineGap);
  229. }
  230. float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
  231. {
  232. return stbtt_ScaleForPixelHeight(&font->font, size);
  233. }
  234. int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
  235. {
  236. return stbtt_FindGlyphIndex(&font->font, codepoint);
  237. }
  238. int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale,
  239. int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1)
  240. {
  241. FONS_NOTUSED(size);
  242. stbtt_GetGlyphHMetrics(&font->font, glyph, advance, lsb);
  243. stbtt_GetGlyphBitmapBox(&font->font, glyph, scale, scale, x0, y0, x1, y1);
  244. return 1;
  245. }
  246. void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride,
  247. float scaleX, float scaleY, int glyph)
  248. {
  249. stbtt_MakeGlyphBitmap(&font->font, output, outWidth, outHeight, outStride, scaleX, scaleY, glyph);
  250. }
  251. int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
  252. {
  253. return stbtt_GetGlyphKernAdvance(&font->font, glyph1, glyph2);
  254. }
  255. #endif
  256. #ifndef FONS_SCRATCH_BUF_SIZE
  257. # define FONS_SCRATCH_BUF_SIZE 64000
  258. #endif
  259. #ifndef FONS_HASH_LUT_SIZE
  260. # define FONS_HASH_LUT_SIZE 256
  261. #endif
  262. #ifndef FONS_INIT_FONTS
  263. # define FONS_INIT_FONTS 4
  264. #endif
  265. #ifndef FONS_INIT_GLYPHS
  266. # define FONS_INIT_GLYPHS 256
  267. #endif
  268. #ifndef FONS_INIT_ATLAS_NODES
  269. # define FONS_INIT_ATLAS_NODES 256
  270. #endif
  271. #ifndef FONS_VERTEX_COUNT
  272. # define FONS_VERTEX_COUNT 1024
  273. #endif
  274. #ifndef FONS_MAX_STATES
  275. # define FONS_MAX_STATES 20
  276. #endif
  277. #ifndef FONS_MAX_FALLBACKS
  278. # define FONS_MAX_FALLBACKS 20
  279. #endif
  280. static unsigned int fons__hashint(unsigned int a)
  281. {
  282. a += ~(a<<15);
  283. a ^= (a>>10);
  284. a += (a<<3);
  285. a ^= (a>>6);
  286. a += ~(a<<11);
  287. a ^= (a>>16);
  288. return a;
  289. }
  290. static int fons__mini(int a, int b)
  291. {
  292. return a < b ? a : b;
  293. }
  294. static int fons__maxi(int a, int b)
  295. {
  296. return a > b ? a : b;
  297. }
  298. struct FONSglyph
  299. {
  300. unsigned int codepoint;
  301. int index;
  302. int next;
  303. short size, blur;
  304. short x0,y0,x1,y1;
  305. short xadv,xoff,yoff;
  306. };
  307. typedef struct FONSglyph FONSglyph;
  308. struct FONSfont
  309. {
  310. FONSttFontImpl font;
  311. char name[64];
  312. unsigned char* data;
  313. int dataSize;
  314. unsigned char freeData;
  315. float ascender;
  316. float descender;
  317. float lineh;
  318. FONSglyph* glyphs;
  319. int cglyphs;
  320. int nglyphs;
  321. int lut[FONS_HASH_LUT_SIZE];
  322. int fallbacks[FONS_MAX_FALLBACKS];
  323. int nfallbacks;
  324. };
  325. typedef struct FONSfont FONSfont;
  326. struct FONSstate
  327. {
  328. int font;
  329. int align;
  330. float size;
  331. unsigned int color;
  332. float blur;
  333. float spacing;
  334. };
  335. typedef struct FONSstate FONSstate;
  336. struct FONSatlasNode {
  337. short x, y, width;
  338. };
  339. typedef struct FONSatlasNode FONSatlasNode;
  340. struct FONSatlas
  341. {
  342. int width, height;
  343. FONSatlasNode* nodes;
  344. int nnodes;
  345. int cnodes;
  346. };
  347. typedef struct FONSatlas FONSatlas;
  348. struct FONScontext
  349. {
  350. FONSparams params;
  351. float itw,ith;
  352. unsigned char* texData;
  353. int dirtyRect[4];
  354. FONSfont** fonts;
  355. FONSatlas* atlas;
  356. int cfonts;
  357. int nfonts;
  358. float verts[FONS_VERTEX_COUNT*2];
  359. float tcoords[FONS_VERTEX_COUNT*2];
  360. unsigned int colors[FONS_VERTEX_COUNT];
  361. int nverts;
  362. unsigned char* scratch;
  363. int nscratch;
  364. FONSstate states[FONS_MAX_STATES];
  365. int nstates;
  366. void (*handleError)(void* uptr, int error, int val);
  367. void* errorUptr;
  368. };
  369. #ifdef STB_TRUETYPE_IMPLEMENTATION
  370. static void* fons__tmpalloc(size_t size, void* up)
  371. {
  372. unsigned char* ptr;
  373. FONScontext* stash = (FONScontext*)up;
  374. // 16-byte align the returned pointer
  375. size = (size + 0xf) & ~0xf;
  376. if (stash->nscratch+(int)size > FONS_SCRATCH_BUF_SIZE) {
  377. if (stash->handleError)
  378. stash->handleError(stash->errorUptr, FONS_SCRATCH_FULL, stash->nscratch+(int)size);
  379. return NULL;
  380. }
  381. ptr = stash->scratch + stash->nscratch;
  382. stash->nscratch += (int)size;
  383. return ptr;
  384. }
  385. static void fons__tmpfree(void* ptr, void* up)
  386. {
  387. (void)ptr;
  388. (void)up;
  389. // empty
  390. }
  391. #endif // STB_TRUETYPE_IMPLEMENTATION
  392. // Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
  393. // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
  394. #define FONS_UTF8_ACCEPT 0
  395. #define FONS_UTF8_REJECT 12
  396. static unsigned int fons__decutf8(unsigned int* state, unsigned int* codep, unsigned int byte)
  397. {
  398. static const unsigned char utf8d[] = {
  399. // The first part of the table maps bytes to character classes that
  400. // to reduce the size of the transition table and create bitmasks.
  401. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  402. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  403. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  404. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  405. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
  406. 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  407. 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  408. 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
  409. // The second part is a transition table that maps a combination
  410. // of a state of the automaton and a character class to a state.
  411. 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
  412. 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
  413. 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
  414. 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
  415. 12,36,12,12,12,12,12,12,12,12,12,12,
  416. };
  417. unsigned int type = utf8d[byte];
  418. *codep = (*state != FONS_UTF8_ACCEPT) ?
  419. (byte & 0x3fu) | (*codep << 6) :
  420. (0xff >> type) & (byte);
  421. *state = utf8d[256 + *state + type];
  422. return *state;
  423. }
  424. // Atlas based on Skyline Bin Packer by Jukka Jylänki
  425. static void fons__deleteAtlas(FONSatlas* atlas)
  426. {
  427. if (atlas == NULL) return;
  428. if (atlas->nodes != NULL) free(atlas->nodes);
  429. free(atlas);
  430. }
  431. static FONSatlas* fons__allocAtlas(int w, int h, int nnodes)
  432. {
  433. FONSatlas* atlas = NULL;
  434. // Allocate memory for the font stash.
  435. atlas = (FONSatlas*)malloc(sizeof(FONSatlas));
  436. if (atlas == NULL) goto error;
  437. memset(atlas, 0, sizeof(FONSatlas));
  438. atlas->width = w;
  439. atlas->height = h;
  440. // Allocate space for skyline nodes
  441. atlas->nodes = (FONSatlasNode*)malloc(sizeof(FONSatlasNode) * nnodes);
  442. if (atlas->nodes == NULL) goto error;
  443. memset(atlas->nodes, 0, sizeof(FONSatlasNode) * nnodes);
  444. atlas->nnodes = 0;
  445. atlas->cnodes = nnodes;
  446. // Init root node.
  447. atlas->nodes[0].x = 0;
  448. atlas->nodes[0].y = 0;
  449. atlas->nodes[0].width = (short)w;
  450. atlas->nnodes++;
  451. return atlas;
  452. error:
  453. if (atlas) fons__deleteAtlas(atlas);
  454. return NULL;
  455. }
  456. static int fons__atlasInsertNode(FONSatlas* atlas, int idx, int x, int y, int w)
  457. {
  458. int i;
  459. // Insert node
  460. if (atlas->nnodes+1 > atlas->cnodes) {
  461. atlas->cnodes = atlas->cnodes == 0 ? 8 : atlas->cnodes * 2;
  462. atlas->nodes = (FONSatlasNode*)realloc(atlas->nodes, sizeof(FONSatlasNode) * atlas->cnodes);
  463. if (atlas->nodes == NULL)
  464. return 0;
  465. }
  466. for (i = atlas->nnodes; i > idx; i--)
  467. atlas->nodes[i] = atlas->nodes[i-1];
  468. atlas->nodes[idx].x = (short)x;
  469. atlas->nodes[idx].y = (short)y;
  470. atlas->nodes[idx].width = (short)w;
  471. atlas->nnodes++;
  472. return 1;
  473. }
  474. static void fons__atlasRemoveNode(FONSatlas* atlas, int idx)
  475. {
  476. int i;
  477. if (atlas->nnodes == 0) return;
  478. for (i = idx; i < atlas->nnodes-1; i++)
  479. atlas->nodes[i] = atlas->nodes[i+1];
  480. atlas->nnodes--;
  481. }
  482. static void fons__atlasExpand(FONSatlas* atlas, int w, int h)
  483. {
  484. // Insert node for empty space
  485. if (w > atlas->width)
  486. fons__atlasInsertNode(atlas, atlas->nnodes, atlas->width, 0, w - atlas->width);
  487. atlas->width = w;
  488. atlas->height = h;
  489. }
  490. static void fons__atlasReset(FONSatlas* atlas, int w, int h)
  491. {
  492. atlas->width = w;
  493. atlas->height = h;
  494. atlas->nnodes = 0;
  495. // Init root node.
  496. atlas->nodes[0].x = 0;
  497. atlas->nodes[0].y = 0;
  498. atlas->nodes[0].width = (short)w;
  499. atlas->nnodes++;
  500. }
  501. static int fons__atlasAddSkylineLevel(FONSatlas* atlas, int idx, int x, int y, int w, int h)
  502. {
  503. int i;
  504. // Insert new node
  505. if (fons__atlasInsertNode(atlas, idx, x, y+h, w) == 0)
  506. return 0;
  507. // Delete skyline segments that fall under the shadow of the new segment.
  508. for (i = idx+1; i < atlas->nnodes; i++) {
  509. if (atlas->nodes[i].x < atlas->nodes[i-1].x + atlas->nodes[i-1].width) {
  510. int shrink = atlas->nodes[i-1].x + atlas->nodes[i-1].width - atlas->nodes[i].x;
  511. atlas->nodes[i].x += (short)shrink;
  512. atlas->nodes[i].width -= (short)shrink;
  513. if (atlas->nodes[i].width <= 0) {
  514. fons__atlasRemoveNode(atlas, i);
  515. i--;
  516. } else {
  517. break;
  518. }
  519. } else {
  520. break;
  521. }
  522. }
  523. // Merge same height skyline segments that are next to each other.
  524. for (i = 0; i < atlas->nnodes-1; i++) {
  525. if (atlas->nodes[i].y == atlas->nodes[i+1].y) {
  526. atlas->nodes[i].width += atlas->nodes[i+1].width;
  527. fons__atlasRemoveNode(atlas, i+1);
  528. i--;
  529. }
  530. }
  531. return 1;
  532. }
  533. static int fons__atlasRectFits(FONSatlas* atlas, int i, int w, int h)
  534. {
  535. // Checks if there is enough space at the location of skyline span 'i',
  536. // and return the max height of all skyline spans under that at that location,
  537. // (think tetris block being dropped at that position). Or -1 if no space found.
  538. int x = atlas->nodes[i].x;
  539. int y = atlas->nodes[i].y;
  540. int spaceLeft;
  541. if (x + w > atlas->width)
  542. return -1;
  543. spaceLeft = w;
  544. while (spaceLeft > 0) {
  545. if (i == atlas->nnodes) return -1;
  546. y = fons__maxi(y, atlas->nodes[i].y);
  547. if (y + h > atlas->height) return -1;
  548. spaceLeft -= atlas->nodes[i].width;
  549. ++i;
  550. }
  551. return y;
  552. }
  553. static int fons__atlasAddRect(FONSatlas* atlas, int rw, int rh, int* rx, int* ry)
  554. {
  555. int besth = atlas->height, bestw = atlas->width, besti = -1;
  556. int bestx = -1, besty = -1, i;
  557. // Bottom left fit heuristic.
  558. for (i = 0; i < atlas->nnodes; i++) {
  559. int y = fons__atlasRectFits(atlas, i, rw, rh);
  560. if (y != -1) {
  561. if (y + rh < besth || (y + rh == besth && atlas->nodes[i].width < bestw)) {
  562. besti = i;
  563. bestw = atlas->nodes[i].width;
  564. besth = y + rh;
  565. bestx = atlas->nodes[i].x;
  566. besty = y;
  567. }
  568. }
  569. }
  570. if (besti == -1)
  571. return 0;
  572. // Perform the actual packing.
  573. if (fons__atlasAddSkylineLevel(atlas, besti, bestx, besty, rw, rh) == 0)
  574. return 0;
  575. *rx = bestx;
  576. *ry = besty;
  577. return 1;
  578. }
  579. static void fons__addWhiteRect(FONScontext* stash, int w, int h)
  580. {
  581. int x, y, gx, gy;
  582. unsigned char* dst;
  583. if (fons__atlasAddRect(stash->atlas, w, h, &gx, &gy) == 0)
  584. return;
  585. // Rasterize
  586. dst = &stash->texData[gx + gy * stash->params.width];
  587. for (y = 0; y < h; y++) {
  588. for (x = 0; x < w; x++)
  589. dst[x] = 0xff;
  590. dst += stash->params.width;
  591. }
  592. stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], gx);
  593. stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], gy);
  594. stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], gx+w);
  595. stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], gy+h);
  596. }
  597. FONScontext* fonsCreateInternal(FONSparams* params)
  598. {
  599. FONScontext* stash = NULL;
  600. // Allocate memory for the font stash.
  601. stash = (FONScontext*)malloc(sizeof(FONScontext));
  602. if (stash == NULL) goto error;
  603. memset(stash, 0, sizeof(FONScontext));
  604. stash->params = *params;
  605. // Allocate scratch buffer.
  606. stash->scratch = (unsigned char*)malloc(FONS_SCRATCH_BUF_SIZE);
  607. if (stash->scratch == NULL) goto error;
  608. // Initialize implementation library
  609. if (!fons__tt_init(stash)) goto error;
  610. if (stash->params.renderCreate != NULL) {
  611. if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0)
  612. goto error;
  613. }
  614. stash->atlas = fons__allocAtlas(stash->params.width, stash->params.height, FONS_INIT_ATLAS_NODES);
  615. if (stash->atlas == NULL) goto error;
  616. // Allocate space for fonts.
  617. stash->fonts = (FONSfont**)malloc(sizeof(FONSfont*) * FONS_INIT_FONTS);
  618. if (stash->fonts == NULL) goto error;
  619. memset(stash->fonts, 0, sizeof(FONSfont*) * FONS_INIT_FONTS);
  620. stash->cfonts = FONS_INIT_FONTS;
  621. stash->nfonts = 0;
  622. // Create texture for the cache.
  623. stash->itw = 1.0f/stash->params.width;
  624. stash->ith = 1.0f/stash->params.height;
  625. stash->texData = (unsigned char*)malloc(stash->params.width * stash->params.height);
  626. if (stash->texData == NULL) goto error;
  627. memset(stash->texData, 0, stash->params.width * stash->params.height);
  628. stash->dirtyRect[0] = stash->params.width;
  629. stash->dirtyRect[1] = stash->params.height;
  630. stash->dirtyRect[2] = 0;
  631. stash->dirtyRect[3] = 0;
  632. // Add white rect at 0,0 for debug drawing.
  633. fons__addWhiteRect(stash, 2,2);
  634. fonsPushState(stash);
  635. fonsClearState(stash);
  636. return stash;
  637. error:
  638. fonsDeleteInternal(stash);
  639. return NULL;
  640. }
  641. static FONSstate* fons__getState(FONScontext* stash)
  642. {
  643. return &stash->states[stash->nstates-1];
  644. }
  645. int fonsAddFallbackFont(FONScontext* stash, int base, int fallback)
  646. {
  647. FONSfont* baseFont = stash->fonts[base];
  648. if (baseFont->nfallbacks < FONS_MAX_FALLBACKS) {
  649. baseFont->fallbacks[baseFont->nfallbacks++] = fallback;
  650. return 1;
  651. }
  652. return 0;
  653. }
  654. void fonsSetSize(FONScontext* stash, float size)
  655. {
  656. fons__getState(stash)->size = size;
  657. }
  658. void fonsSetColor(FONScontext* stash, unsigned int color)
  659. {
  660. fons__getState(stash)->color = color;
  661. }
  662. void fonsSetSpacing(FONScontext* stash, float spacing)
  663. {
  664. fons__getState(stash)->spacing = spacing;
  665. }
  666. void fonsSetBlur(FONScontext* stash, float blur)
  667. {
  668. fons__getState(stash)->blur = blur;
  669. }
  670. void fonsSetAlign(FONScontext* stash, int align)
  671. {
  672. fons__getState(stash)->align = align;
  673. }
  674. void fonsSetFont(FONScontext* stash, int font)
  675. {
  676. fons__getState(stash)->font = font;
  677. }
  678. void fonsPushState(FONScontext* stash)
  679. {
  680. if (stash->nstates >= FONS_MAX_STATES) {
  681. if (stash->handleError)
  682. stash->handleError(stash->errorUptr, FONS_STATES_OVERFLOW, 0);
  683. return;
  684. }
  685. if (stash->nstates > 0)
  686. memcpy(&stash->states[stash->nstates], &stash->states[stash->nstates-1], sizeof(FONSstate));
  687. stash->nstates++;
  688. }
  689. void fonsPopState(FONScontext* stash)
  690. {
  691. if (stash->nstates <= 1) {
  692. if (stash->handleError)
  693. stash->handleError(stash->errorUptr, FONS_STATES_UNDERFLOW, 0);
  694. return;
  695. }
  696. stash->nstates--;
  697. }
  698. void fonsClearState(FONScontext* stash)
  699. {
  700. FONSstate* state = fons__getState(stash);
  701. state->size = 12.0f;
  702. state->color = 0xffffffff;
  703. state->font = 0;
  704. state->blur = 0;
  705. state->spacing = 0;
  706. state->align = FONS_ALIGN_LEFT | FONS_ALIGN_BASELINE;
  707. }
  708. static void fons__freeFont(FONSfont* font)
  709. {
  710. if (font == NULL) return;
  711. if (font->glyphs) free(font->glyphs);
  712. if (font->freeData && font->data) free(font->data);
  713. free(font);
  714. }
  715. static int fons__allocFont(FONScontext* stash)
  716. {
  717. FONSfont* font = NULL;
  718. if (stash->nfonts+1 > stash->cfonts) {
  719. stash->cfonts = stash->cfonts == 0 ? 8 : stash->cfonts * 2;
  720. stash->fonts = (FONSfont**)realloc(stash->fonts, sizeof(FONSfont*) * stash->cfonts);
  721. if (stash->fonts == NULL)
  722. return -1;
  723. }
  724. font = (FONSfont*)malloc(sizeof(FONSfont));
  725. if (font == NULL) goto error;
  726. memset(font, 0, sizeof(FONSfont));
  727. font->glyphs = (FONSglyph*)malloc(sizeof(FONSglyph) * FONS_INIT_GLYPHS);
  728. if (font->glyphs == NULL) goto error;
  729. font->cglyphs = FONS_INIT_GLYPHS;
  730. font->nglyphs = 0;
  731. stash->fonts[stash->nfonts++] = font;
  732. return stash->nfonts-1;
  733. error:
  734. fons__freeFont(font);
  735. return FONS_INVALID;
  736. }
  737. int fonsAddFont(FONScontext* stash, const char* name, const char* path)
  738. {
  739. FILE* fp = 0;
  740. int dataSize = 0;
  741. size_t readed;
  742. unsigned char* data = NULL;
  743. // Read in the font data.
  744. fp = fopen(path, "rb");
  745. if (fp == NULL) goto error;
  746. fseek(fp,0,SEEK_END);
  747. dataSize = (int)ftell(fp);
  748. fseek(fp,0,SEEK_SET);
  749. data = (unsigned char*)malloc(dataSize);
  750. if (data == NULL) goto error;
  751. readed = fread(data, 1, dataSize, fp);
  752. fclose(fp);
  753. fp = 0;
  754. if (readed != dataSize) goto error;
  755. return fonsAddFontMem(stash, name, data, dataSize, 1);
  756. error:
  757. if (data) free(data);
  758. if (fp) fclose(fp);
  759. return FONS_INVALID;
  760. }
  761. int fonsAddFontMem(FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData)
  762. {
  763. int i, ascent, descent, fh, lineGap;
  764. FONSfont* font;
  765. int idx = fons__allocFont(stash);
  766. if (idx == FONS_INVALID)
  767. return FONS_INVALID;
  768. font = stash->fonts[idx];
  769. strncpy(font->name, name, sizeof(font->name));
  770. font->name[sizeof(font->name)-1] = '\0';
  771. // Init hash lookup.
  772. for (i = 0; i < FONS_HASH_LUT_SIZE; ++i)
  773. font->lut[i] = -1;
  774. // Read in the font data.
  775. font->dataSize = dataSize;
  776. font->data = data;
  777. font->freeData = (unsigned char)freeData;
  778. // Init font
  779. stash->nscratch = 0;
  780. if (!fons__tt_loadFont(stash, &font->font, data, dataSize)) goto error;
  781. // Store normalized line height. The real line height is got
  782. // by multiplying the lineh by font size.
  783. fons__tt_getFontVMetrics( &font->font, &ascent, &descent, &lineGap);
  784. fh = ascent - descent;
  785. font->ascender = (float)ascent / (float)fh;
  786. font->descender = (float)descent / (float)fh;
  787. font->lineh = (float)(fh + lineGap) / (float)fh;
  788. return idx;
  789. error:
  790. fons__freeFont(font);
  791. stash->nfonts--;
  792. return FONS_INVALID;
  793. }
  794. int fonsGetFontByName(FONScontext* s, const char* name)
  795. {
  796. int i;
  797. for (i = 0; i < s->nfonts; i++) {
  798. if (strcmp(s->fonts[i]->name, name) == 0)
  799. return i;
  800. }
  801. return FONS_INVALID;
  802. }
  803. static FONSglyph* fons__allocGlyph(FONSfont* font)
  804. {
  805. if (font->nglyphs+1 > font->cglyphs) {
  806. font->cglyphs = font->cglyphs == 0 ? 8 : font->cglyphs * 2;
  807. font->glyphs = (FONSglyph*)realloc(font->glyphs, sizeof(FONSglyph) * font->cglyphs);
  808. if (font->glyphs == NULL) return NULL;
  809. }
  810. font->nglyphs++;
  811. return &font->glyphs[font->nglyphs-1];
  812. }
  813. // Based on Exponential blur, Jani Huhtanen, 2006
  814. #define APREC 16
  815. #define ZPREC 7
  816. static void fons__blurCols(unsigned char* dst, int w, int h, int dstStride, int alpha)
  817. {
  818. int x, y;
  819. for (y = 0; y < h; y++) {
  820. int z = 0; // force zero border
  821. for (x = 1; x < w; x++) {
  822. z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
  823. dst[x] = (unsigned char)(z >> ZPREC);
  824. }
  825. dst[w-1] = 0; // force zero border
  826. z = 0;
  827. for (x = w-2; x >= 0; x--) {
  828. z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
  829. dst[x] = (unsigned char)(z >> ZPREC);
  830. }
  831. dst[0] = 0; // force zero border
  832. dst += dstStride;
  833. }
  834. }
  835. static void fons__blurRows(unsigned char* dst, int w, int h, int dstStride, int alpha)
  836. {
  837. int x, y;
  838. for (x = 0; x < w; x++) {
  839. int z = 0; // force zero border
  840. for (y = dstStride; y < h*dstStride; y += dstStride) {
  841. z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
  842. dst[y] = (unsigned char)(z >> ZPREC);
  843. }
  844. dst[(h-1)*dstStride] = 0; // force zero border
  845. z = 0;
  846. for (y = (h-2)*dstStride; y >= 0; y -= dstStride) {
  847. z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
  848. dst[y] = (unsigned char)(z >> ZPREC);
  849. }
  850. dst[0] = 0; // force zero border
  851. dst++;
  852. }
  853. }
  854. static void fons__blur(FONScontext* stash, unsigned char* dst, int w, int h, int dstStride, int blur)
  855. {
  856. int alpha;
  857. float sigma;
  858. (void)stash;
  859. if (blur < 1)
  860. return;
  861. // Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity)
  862. sigma = (float)blur * 0.57735f; // 1 / sqrt(3)
  863. alpha = (int)((1<<APREC) * (1.0f - expf(-2.3f / (sigma+1.0f))));
  864. fons__blurRows(dst, w, h, dstStride, alpha);
  865. fons__blurCols(dst, w, h, dstStride, alpha);
  866. fons__blurRows(dst, w, h, dstStride, alpha);
  867. fons__blurCols(dst, w, h, dstStride, alpha);
  868. // fons__blurrows(dst, w, h, dstStride, alpha);
  869. // fons__blurcols(dst, w, h, dstStride, alpha);
  870. }
  871. static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned int codepoint,
  872. short isize, short iblur)
  873. {
  874. int i, g, advance, lsb, x0, y0, x1, y1, gw, gh, gx, gy, x, y;
  875. float scale;
  876. FONSglyph* glyph = NULL;
  877. unsigned int h;
  878. float size = isize/10.0f;
  879. int pad, added;
  880. unsigned char* bdst;
  881. unsigned char* dst;
  882. FONSfont* renderFont = font;
  883. if (isize < 2) return NULL;
  884. if (iblur > 20) iblur = 20;
  885. pad = iblur+2;
  886. // Reset allocator.
  887. stash->nscratch = 0;
  888. // Find code point and size.
  889. h = fons__hashint(codepoint) & (FONS_HASH_LUT_SIZE-1);
  890. i = font->lut[h];
  891. while (i != -1) {
  892. if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur)
  893. return &font->glyphs[i];
  894. i = font->glyphs[i].next;
  895. }
  896. // Could not find glyph, create it.
  897. g = fons__tt_getGlyphIndex(&font->font, codepoint);
  898. // Try to find the glyph in fallback fonts.
  899. if (g == 0) {
  900. for (i = 0; i < font->nfallbacks; ++i) {
  901. FONSfont* fallbackFont = stash->fonts[font->fallbacks[i]];
  902. int fallbackIndex = fons__tt_getGlyphIndex(&fallbackFont->font, codepoint);
  903. if (fallbackIndex != 0) {
  904. g = fallbackIndex;
  905. renderFont = fallbackFont;
  906. break;
  907. }
  908. }
  909. // It is possible that we did not find a fallback glyph.
  910. // In that case the glyph index 'g' is 0, and we'll proceed below and cache empty glyph.
  911. }
  912. scale = fons__tt_getPixelHeightScale(&renderFont->font, size);
  913. fons__tt_buildGlyphBitmap(&renderFont->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1);
  914. gw = x1-x0 + pad*2;
  915. gh = y1-y0 + pad*2;
  916. // Find free spot for the rect in the atlas
  917. added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
  918. if (added == 0 && stash->handleError != NULL) {
  919. // Atlas is full, let the user to resize the atlas (or not), and try again.
  920. stash->handleError(stash->errorUptr, FONS_ATLAS_FULL, 0);
  921. added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
  922. }
  923. if (added == 0) return NULL;
  924. // Init glyph.
  925. glyph = fons__allocGlyph(font);
  926. glyph->codepoint = codepoint;
  927. glyph->size = isize;
  928. glyph->blur = iblur;
  929. glyph->index = g;
  930. glyph->x0 = (short)gx;
  931. glyph->y0 = (short)gy;
  932. glyph->x1 = (short)(glyph->x0+gw);
  933. glyph->y1 = (short)(glyph->y0+gh);
  934. glyph->xadv = (short)(scale * advance * 10.0f);
  935. glyph->xoff = (short)(x0 - pad);
  936. glyph->yoff = (short)(y0 - pad);
  937. glyph->next = 0;
  938. // Insert char to hash lookup.
  939. glyph->next = font->lut[h];
  940. font->lut[h] = font->nglyphs-1;
  941. // Rasterize
  942. dst = &stash->texData[(glyph->x0+pad) + (glyph->y0+pad) * stash->params.width];
  943. fons__tt_renderGlyphBitmap(&renderFont->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale,scale, g);
  944. // Make sure there is one pixel empty border.
  945. dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
  946. for (y = 0; y < gh; y++) {
  947. dst[y*stash->params.width] = 0;
  948. dst[gw-1 + y*stash->params.width] = 0;
  949. }
  950. for (x = 0; x < gw; x++) {
  951. dst[x] = 0;
  952. dst[x + (gh-1)*stash->params.width] = 0;
  953. }
  954. // Debug code to color the glyph background
  955. /* unsigned char* fdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
  956. for (y = 0; y < gh; y++) {
  957. for (x = 0; x < gw; x++) {
  958. int a = (int)fdst[x+y*stash->params.width] + 20;
  959. if (a > 255) a = 255;
  960. fdst[x+y*stash->params.width] = a;
  961. }
  962. }*/
  963. // Blur
  964. if (iblur > 0) {
  965. stash->nscratch = 0;
  966. bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
  967. fons__blur(stash, bdst, gw,gh, stash->params.width, iblur);
  968. }
  969. stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0);
  970. stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], glyph->y0);
  971. stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], glyph->x1);
  972. stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], glyph->y1);
  973. return glyph;
  974. }
  975. static void fons__getQuad(FONScontext* stash, FONSfont* font,
  976. int prevGlyphIndex, FONSglyph* glyph,
  977. float scale, float spacing, float* x, float* y, FONSquad* q)
  978. {
  979. float rx,ry,xoff,yoff,x0,y0,x1,y1;
  980. if (prevGlyphIndex != -1) {
  981. float adv = fons__tt_getGlyphKernAdvance(&font->font, prevGlyphIndex, glyph->index) * scale;
  982. *x += (int)(adv + spacing + 0.5f);
  983. }
  984. // Each glyph has 2px border to allow good interpolation,
  985. // one pixel to prevent leaking, and one to allow good interpolation for rendering.
  986. // Inset the texture region by one pixel for correct interpolation.
  987. xoff = (short)(glyph->xoff+1);
  988. yoff = (short)(glyph->yoff+1);
  989. x0 = (float)(glyph->x0+1);
  990. y0 = (float)(glyph->y0+1);
  991. x1 = (float)(glyph->x1-1);
  992. y1 = (float)(glyph->y1-1);
  993. if (stash->params.flags & FONS_ZERO_TOPLEFT) {
  994. rx = (float)(int)(*x + xoff);
  995. ry = (float)(int)(*y + yoff);
  996. q->x0 = rx;
  997. q->y0 = ry;
  998. q->x1 = rx + x1 - x0;
  999. q->y1 = ry + y1 - y0;
  1000. q->s0 = x0 * stash->itw;
  1001. q->t0 = y0 * stash->ith;
  1002. q->s1 = x1 * stash->itw;
  1003. q->t1 = y1 * stash->ith;
  1004. } else {
  1005. rx = (float)(int)(*x + xoff);
  1006. ry = (float)(int)(*y - yoff);
  1007. q->x0 = rx;
  1008. q->y0 = ry;
  1009. q->x1 = rx + x1 - x0;
  1010. q->y1 = ry - y1 + y0;
  1011. q->s0 = x0 * stash->itw;
  1012. q->t0 = y0 * stash->ith;
  1013. q->s1 = x1 * stash->itw;
  1014. q->t1 = y1 * stash->ith;
  1015. }
  1016. *x += (int)(glyph->xadv / 10.0f + 0.5f);
  1017. }
  1018. static void fons__flush(FONScontext* stash)
  1019. {
  1020. // Flush texture
  1021. if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
  1022. if (stash->params.renderUpdate != NULL)
  1023. stash->params.renderUpdate(stash->params.userPtr, stash->dirtyRect, stash->texData);
  1024. // Reset dirty rect
  1025. stash->dirtyRect[0] = stash->params.width;
  1026. stash->dirtyRect[1] = stash->params.height;
  1027. stash->dirtyRect[2] = 0;
  1028. stash->dirtyRect[3] = 0;
  1029. }
  1030. // Flush triangles
  1031. if (stash->nverts > 0) {
  1032. if (stash->params.renderDraw != NULL)
  1033. stash->params.renderDraw(stash->params.userPtr, stash->verts, stash->tcoords, stash->colors, stash->nverts);
  1034. stash->nverts = 0;
  1035. }
  1036. }
  1037. static __inline void fons__vertex(FONScontext* stash, float x, float y, float s, float t, unsigned int c)
  1038. {
  1039. stash->verts[stash->nverts*2+0] = x;
  1040. stash->verts[stash->nverts*2+1] = y;
  1041. stash->tcoords[stash->nverts*2+0] = s;
  1042. stash->tcoords[stash->nverts*2+1] = t;
  1043. stash->colors[stash->nverts] = c;
  1044. stash->nverts++;
  1045. }
  1046. static float fons__getVertAlign(FONScontext* stash, FONSfont* font, int align, short isize)
  1047. {
  1048. if (stash->params.flags & FONS_ZERO_TOPLEFT) {
  1049. if (align & FONS_ALIGN_TOP) {
  1050. return font->ascender * (float)isize/10.0f;
  1051. } else if (align & FONS_ALIGN_MIDDLE) {
  1052. return (font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
  1053. } else if (align & FONS_ALIGN_BASELINE) {
  1054. return 0.0f;
  1055. } else if (align & FONS_ALIGN_BOTTOM) {
  1056. return font->descender * (float)isize/10.0f;
  1057. }
  1058. } else {
  1059. if (align & FONS_ALIGN_TOP) {
  1060. return -font->ascender * (float)isize/10.0f;
  1061. } else if (align & FONS_ALIGN_MIDDLE) {
  1062. return -(font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
  1063. } else if (align & FONS_ALIGN_BASELINE) {
  1064. return 0.0f;
  1065. } else if (align & FONS_ALIGN_BOTTOM) {
  1066. return -font->descender * (float)isize/10.0f;
  1067. }
  1068. }
  1069. return 0.0;
  1070. }
  1071. float fonsDrawText(FONScontext* stash,
  1072. float x, float y,
  1073. const char* str, const char* end)
  1074. {
  1075. FONSstate* state = fons__getState(stash);
  1076. unsigned int codepoint;
  1077. unsigned int utf8state = 0;
  1078. FONSglyph* glyph = NULL;
  1079. FONSquad q;
  1080. int prevGlyphIndex = -1;
  1081. short isize = (short)(state->size*10.0f);
  1082. short iblur = (short)state->blur;
  1083. float scale;
  1084. FONSfont* font;
  1085. float width;
  1086. if (stash == NULL) return x;
  1087. if (state->font < 0 || state->font >= stash->nfonts) return x;
  1088. font = stash->fonts[state->font];
  1089. if (font->data == NULL) return x;
  1090. scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f);
  1091. if (end == NULL)
  1092. end = str + strlen(str);
  1093. // Align horizontally
  1094. if (state->align & FONS_ALIGN_LEFT) {
  1095. // empty
  1096. } else if (state->align & FONS_ALIGN_RIGHT) {
  1097. width = fonsTextBounds(stash, x,y, str, end, NULL);
  1098. x -= width;
  1099. } else if (state->align & FONS_ALIGN_CENTER) {
  1100. width = fonsTextBounds(stash, x,y, str, end, NULL);
  1101. x -= width * 0.5f;
  1102. }
  1103. // Align vertically.
  1104. y += fons__getVertAlign(stash, font, state->align, isize);
  1105. for (; str != end; ++str) {
  1106. if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
  1107. continue;
  1108. glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
  1109. if (glyph != NULL) {
  1110. fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
  1111. if (stash->nverts+6 > FONS_VERTEX_COUNT)
  1112. fons__flush(stash);
  1113. fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->color);
  1114. fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->color);
  1115. fons__vertex(stash, q.x1, q.y0, q.s1, q.t0, state->color);
  1116. fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->color);
  1117. fons__vertex(stash, q.x0, q.y1, q.s0, q.t1, state->color);
  1118. fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->color);
  1119. }
  1120. prevGlyphIndex = glyph != NULL ? glyph->index : -1;
  1121. }
  1122. fons__flush(stash);
  1123. return x;
  1124. }
  1125. int fonsTextIterInit(FONScontext* stash, FONStextIter* iter,
  1126. float x, float y, const char* str, const char* end)
  1127. {
  1128. FONSstate* state = fons__getState(stash);
  1129. float width;
  1130. memset(iter, 0, sizeof(*iter));
  1131. if (stash == NULL) return 0;
  1132. if (state->font < 0 || state->font >= stash->nfonts) return 0;
  1133. iter->font = stash->fonts[state->font];
  1134. if (iter->font->data == NULL) return 0;
  1135. iter->isize = (short)(state->size*10.0f);
  1136. iter->iblur = (short)state->blur;
  1137. iter->scale = fons__tt_getPixelHeightScale(&iter->font->font, (float)iter->isize/10.0f);
  1138. // Align horizontally
  1139. if (state->align & FONS_ALIGN_LEFT) {
  1140. // empty
  1141. } else if (state->align & FONS_ALIGN_RIGHT) {
  1142. width = fonsTextBounds(stash, x,y, str, end, NULL);
  1143. x -= width;
  1144. } else if (state->align & FONS_ALIGN_CENTER) {
  1145. width = fonsTextBounds(stash, x,y, str, end, NULL);
  1146. x -= width * 0.5f;
  1147. }
  1148. // Align vertically.
  1149. y += fons__getVertAlign(stash, iter->font, state->align, iter->isize);
  1150. if (end == NULL)
  1151. end = str + strlen(str);
  1152. iter->x = iter->nextx = x;
  1153. iter->y = iter->nexty = y;
  1154. iter->spacing = state->spacing;
  1155. iter->str = str;
  1156. iter->next = str;
  1157. iter->end = end;
  1158. iter->codepoint = 0;
  1159. iter->prevGlyphIndex = -1;
  1160. return 1;
  1161. }
  1162. int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, FONSquad* quad)
  1163. {
  1164. FONSglyph* glyph = NULL;
  1165. const char* str = iter->next;
  1166. iter->str = iter->next;
  1167. if (str == iter->end)
  1168. return 0;
  1169. for (; str != iter->end; str++) {
  1170. if (fons__decutf8(&iter->utf8state, &iter->codepoint, *(const unsigned char*)str))
  1171. continue;
  1172. str++;
  1173. // Get glyph and quad
  1174. iter->x = iter->nextx;
  1175. iter->y = iter->nexty;
  1176. glyph = fons__getGlyph(stash, iter->font, iter->codepoint, iter->isize, iter->iblur);
  1177. if (glyph != NULL)
  1178. fons__getQuad(stash, iter->font, iter->prevGlyphIndex, glyph, iter->scale, iter->spacing, &iter->nextx, &iter->nexty, quad);
  1179. iter->prevGlyphIndex = glyph != NULL ? glyph->index : -1;
  1180. break;
  1181. }
  1182. iter->next = str;
  1183. return 1;
  1184. }
  1185. void fonsDrawDebug(FONScontext* stash, float x, float y)
  1186. {
  1187. int i;
  1188. int w = stash->params.width;
  1189. int h = stash->params.height;
  1190. float u = w == 0 ? 0 : (1.0f / w);
  1191. float v = h == 0 ? 0 : (1.0f / h);
  1192. if (stash->nverts+6+6 > FONS_VERTEX_COUNT)
  1193. fons__flush(stash);
  1194. // Draw background
  1195. fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff);
  1196. fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff);
  1197. fons__vertex(stash, x+w, y+0, u, v, 0x0fffffff);
  1198. fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff);
  1199. fons__vertex(stash, x+0, y+h, u, v, 0x0fffffff);
  1200. fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff);
  1201. // Draw texture
  1202. fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff);
  1203. fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff);
  1204. fons__vertex(stash, x+w, y+0, 1, 0, 0xffffffff);
  1205. fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff);
  1206. fons__vertex(stash, x+0, y+h, 0, 1, 0xffffffff);
  1207. fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff);
  1208. // Drawbug draw atlas
  1209. for (i = 0; i < stash->atlas->nnodes; i++) {
  1210. FONSatlasNode* n = &stash->atlas->nodes[i];
  1211. if (stash->nverts+6 > FONS_VERTEX_COUNT)
  1212. fons__flush(stash);
  1213. fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff);
  1214. fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff);
  1215. fons__vertex(stash, x+n->x+n->width, y+n->y+0, u, v, 0xc00000ff);
  1216. fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff);
  1217. fons__vertex(stash, x+n->x+0, y+n->y+1, u, v, 0xc00000ff);
  1218. fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff);
  1219. }
  1220. fons__flush(stash);
  1221. }
  1222. float fonsTextBounds(FONScontext* stash,
  1223. float x, float y,
  1224. const char* str, const char* end,
  1225. float* bounds)
  1226. {
  1227. FONSstate* state = fons__getState(stash);
  1228. unsigned int codepoint;
  1229. unsigned int utf8state = 0;
  1230. FONSquad q;
  1231. FONSglyph* glyph = NULL;
  1232. int prevGlyphIndex = -1;
  1233. short isize = (short)(state->size*10.0f);
  1234. short iblur = (short)state->blur;
  1235. float scale;
  1236. FONSfont* font;
  1237. float startx, advance;
  1238. float minx, miny, maxx, maxy;
  1239. if (stash == NULL) return 0;
  1240. if (state->font < 0 || state->font >= stash->nfonts) return 0;
  1241. font = stash->fonts[state->font];
  1242. if (font->data == NULL) return 0;
  1243. scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f);
  1244. // Align vertically.
  1245. y += fons__getVertAlign(stash, font, state->align, isize);
  1246. minx = maxx = x;
  1247. miny = maxy = y;
  1248. startx = x;
  1249. if (end == NULL)
  1250. end = str + strlen(str);
  1251. for (; str != end; ++str) {
  1252. if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
  1253. continue;
  1254. glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
  1255. if (glyph != NULL) {
  1256. fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
  1257. if (q.x0 < minx) minx = q.x0;
  1258. if (q.x1 > maxx) maxx = q.x1;
  1259. if (stash->params.flags & FONS_ZERO_TOPLEFT) {
  1260. if (q.y0 < miny) miny = q.y0;
  1261. if (q.y1 > maxy) maxy = q.y1;
  1262. } else {
  1263. if (q.y1 < miny) miny = q.y1;
  1264. if (q.y0 > maxy) maxy = q.y0;
  1265. }
  1266. }
  1267. prevGlyphIndex = glyph != NULL ? glyph->index : -1;
  1268. }
  1269. advance = x - startx;
  1270. // Align horizontally
  1271. if (state->align & FONS_ALIGN_LEFT) {
  1272. // empty
  1273. } else if (state->align & FONS_ALIGN_RIGHT) {
  1274. minx -= advance;
  1275. maxx -= advance;
  1276. } else if (state->align & FONS_ALIGN_CENTER) {
  1277. minx -= advance * 0.5f;
  1278. maxx -= advance * 0.5f;
  1279. }
  1280. if (bounds) {
  1281. bounds[0] = minx;
  1282. bounds[1] = miny;
  1283. bounds[2] = maxx;
  1284. bounds[3] = maxy;
  1285. }
  1286. return advance;
  1287. }
  1288. void fonsVertMetrics(FONScontext* stash,
  1289. float* ascender, float* descender, float* lineh)
  1290. {
  1291. FONSfont* font;
  1292. FONSstate* state = fons__getState(stash);
  1293. short isize;
  1294. if (stash == NULL) return;
  1295. if (state->font < 0 || state->font >= stash->nfonts) return;
  1296. font = stash->fonts[state->font];
  1297. isize = (short)(state->size*10.0f);
  1298. if (font->data == NULL) return;
  1299. if (ascender)
  1300. *ascender = font->ascender*isize/10.0f;
  1301. if (descender)
  1302. *descender = font->descender*isize/10.0f;
  1303. if (lineh)
  1304. *lineh = font->lineh*isize/10.0f;
  1305. }
  1306. void fonsLineBounds(FONScontext* stash, float y, float* miny, float* maxy)
  1307. {
  1308. FONSfont* font;
  1309. FONSstate* state = fons__getState(stash);
  1310. short isize;
  1311. if (stash == NULL) return;
  1312. if (state->font < 0 || state->font >= stash->nfonts) return;
  1313. font = stash->fonts[state->font];
  1314. isize = (short)(state->size*10.0f);
  1315. if (font->data == NULL) return;
  1316. y += fons__getVertAlign(stash, font, state->align, isize);
  1317. if (stash->params.flags & FONS_ZERO_TOPLEFT) {
  1318. *miny = y - font->ascender * (float)isize/10.0f;
  1319. *maxy = *miny + font->lineh*isize/10.0f;
  1320. } else {
  1321. *maxy = y + font->descender * (float)isize/10.0f;
  1322. *miny = *maxy - font->lineh*isize/10.0f;
  1323. }
  1324. }
  1325. const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height)
  1326. {
  1327. if (width != NULL)
  1328. *width = stash->params.width;
  1329. if (height != NULL)
  1330. *height = stash->params.height;
  1331. return stash->texData;
  1332. }
  1333. int fonsValidateTexture(FONScontext* stash, int* dirty)
  1334. {
  1335. if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
  1336. dirty[0] = stash->dirtyRect[0];
  1337. dirty[1] = stash->dirtyRect[1];
  1338. dirty[2] = stash->dirtyRect[2];
  1339. dirty[3] = stash->dirtyRect[3];
  1340. // Reset dirty rect
  1341. stash->dirtyRect[0] = stash->params.width;
  1342. stash->dirtyRect[1] = stash->params.height;
  1343. stash->dirtyRect[2] = 0;
  1344. stash->dirtyRect[3] = 0;
  1345. return 1;
  1346. }
  1347. return 0;
  1348. }
  1349. void fonsDeleteInternal(FONScontext* stash)
  1350. {
  1351. int i;
  1352. if (stash == NULL) return;
  1353. if (stash->params.renderDelete)
  1354. stash->params.renderDelete(stash->params.userPtr);
  1355. for (i = 0; i < stash->nfonts; ++i)
  1356. fons__freeFont(stash->fonts[i]);
  1357. if (stash->atlas) fons__deleteAtlas(stash->atlas);
  1358. if (stash->fonts) free(stash->fonts);
  1359. if (stash->texData) free(stash->texData);
  1360. if (stash->scratch) free(stash->scratch);
  1361. free(stash);
  1362. }
  1363. void fonsSetErrorCallback(FONScontext* stash, void (*callback)(void* uptr, int error, int val), void* uptr)
  1364. {
  1365. if (stash == NULL) return;
  1366. stash->handleError = callback;
  1367. stash->errorUptr = uptr;
  1368. }
  1369. void fonsGetAtlasSize(FONScontext* stash, int* width, int* height)
  1370. {
  1371. if (stash == NULL) return;
  1372. *width = stash->params.width;
  1373. *height = stash->params.height;
  1374. }
  1375. int fonsExpandAtlas(FONScontext* stash, int width, int height)
  1376. {
  1377. int i, maxy = 0;
  1378. unsigned char* data = NULL;
  1379. if (stash == NULL) return 0;
  1380. width = fons__maxi(width, stash->params.width);
  1381. height = fons__maxi(height, stash->params.height);
  1382. if (width == stash->params.width && height == stash->params.height)
  1383. return 1;
  1384. // Flush pending glyphs.
  1385. fons__flush(stash);
  1386. // Create new texture
  1387. if (stash->params.renderResize != NULL) {
  1388. if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
  1389. return 0;
  1390. }
  1391. // Copy old texture data over.
  1392. data = (unsigned char*)malloc(width * height);
  1393. if (data == NULL)
  1394. return 0;
  1395. for (i = 0; i < stash->params.height; i++) {
  1396. unsigned char* dst = &data[i*width];
  1397. unsigned char* src = &stash->texData[i*stash->params.width];
  1398. memcpy(dst, src, stash->params.width);
  1399. if (width > stash->params.width)
  1400. memset(dst+stash->params.width, 0, width - stash->params.width);
  1401. }
  1402. if (height > stash->params.height)
  1403. memset(&data[stash->params.height * width], 0, (height - stash->params.height) * width);
  1404. free(stash->texData);
  1405. stash->texData = data;
  1406. // Increase atlas size
  1407. fons__atlasExpand(stash->atlas, width, height);
  1408. // Add existing data as dirty.
  1409. for (i = 0; i < stash->atlas->nnodes; i++)
  1410. maxy = fons__maxi(maxy, stash->atlas->nodes[i].y);
  1411. stash->dirtyRect[0] = 0;
  1412. stash->dirtyRect[1] = 0;
  1413. stash->dirtyRect[2] = stash->params.width;
  1414. stash->dirtyRect[3] = maxy;
  1415. stash->params.width = width;
  1416. stash->params.height = height;
  1417. stash->itw = 1.0f/stash->params.width;
  1418. stash->ith = 1.0f/stash->params.height;
  1419. return 1;
  1420. }
  1421. int fonsResetAtlas(FONScontext* stash, int width, int height)
  1422. {
  1423. int i, j;
  1424. if (stash == NULL) return 0;
  1425. // Flush pending glyphs.
  1426. fons__flush(stash);
  1427. // Create new texture
  1428. if (stash->params.renderResize != NULL) {
  1429. if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
  1430. return 0;
  1431. }
  1432. // Reset atlas
  1433. fons__atlasReset(stash->atlas, width, height);
  1434. // Clear texture data.
  1435. stash->texData = (unsigned char*)realloc(stash->texData, width * height);
  1436. if (stash->texData == NULL) return 0;
  1437. memset(stash->texData, 0, width * height);
  1438. // Reset dirty rect
  1439. stash->dirtyRect[0] = width;
  1440. stash->dirtyRect[1] = height;
  1441. stash->dirtyRect[2] = 0;
  1442. stash->dirtyRect[3] = 0;
  1443. // Reset cached glyphs
  1444. for (i = 0; i < stash->nfonts; i++) {
  1445. FONSfont* font = stash->fonts[i];
  1446. font->nglyphs = 0;
  1447. for (j = 0; j < FONS_HASH_LUT_SIZE; j++)
  1448. font->lut[j] = -1;
  1449. }
  1450. stash->params.width = width;
  1451. stash->params.height = height;
  1452. stash->itw = 1.0f/stash->params.width;
  1453. stash->ith = 1.0f/stash->params.height;
  1454. // Add white rect at 0,0 for debug drawing.
  1455. fons__addWhiteRect(stash, 2,2);
  1456. return 1;
  1457. }
  1458. #endif