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