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