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