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