packages feed

nanovg 0.6.0.0 → 0.7.0.0

raw patch · 12 files changed

+5364/−3363 lines, 12 filesnew-uploader

Files

example/Example.hs view
@@ -76,6 +76,8 @@       drawScissor c 50 (fromIntegral h-80) (realToFrac t) +     drawComposite c+      save c      let popy = 95 + 24      drawThumbnails c 365 popy 160 300 (images demoData) (realToFrac t)@@ -600,6 +602,35 @@      fill c       restore c++drawComposite :: Context -> IO ()+drawComposite c = do+  -- The example in https://github.com/memononen/nanovg/pull/298 implies the+  -- need to call beginFrame/endFrame, but it does not seem to be necessary+  save c++  -- Clears a fragment of the background+  globalCompositeOperation c DestinationOut+  beginPath c+  rect c 50 50 100 100+  fillColor c (rgb 0 0 0)+  fill c++  -- Draws a red circle+  globalCompositeOperation c SourceOver+  beginPath c+  circle c 100 100 30+  fillColor c (rgb 255 0 0)+  fill c++  -- Draws a blue, rounded, rectangle behind the red circle+  globalCompositeOperation c DestinationOver+  beginPath c+  roundedRectVarying c 60 60 80 60 20 10 20 10+  fillColor c (rgb 0 0 255)+  fill c++  restore c  clamp :: Ord a => a -> a -> a -> a clamp a' low up
nanovg.cabal view
@@ -1,5 +1,5 @@ name:                nanovg-version:             0.6.0.0+version:             0.7.0.0 synopsis:            Haskell bindings for nanovg description:         Raw bindings to the OpenGL vector graphics library NanoVG homepage:            https://github.com/cocreature/nanovg-hs@@ -36,28 +36,37 @@   manual:      True  library-  exposed-modules:     NanoVG-                       NanoVG.Internal-                       NanoVG.Internal.Color-                       NanoVG.Internal.CreateContext-                       NanoVG.Internal.Context-                       NanoVG.Internal.FFIHelpers-                       NanoVG.Internal.FixedVector-                       NanoVG.Internal.GL3+  exposed-modules:+                   NanoVG+                   NanoVG.Internal+                   NanoVG.Internal.Color+                   NanoVG.Internal.CreateContext+                   NanoVG.Internal.Context+                   NanoVG.Internal.FFIHelpers+                   NanoVG.Internal.FixedVector+                   NanoVG.Internal.GlobalComposite+                   NanoVG.Internal.Image+                   NanoVG.Internal.Paint+                   NanoVG.Internal.Path+                   NanoVG.Internal.Scissor+                   NanoVG.Internal.State+                   NanoVG.Internal.Style+                   NanoVG.Internal.Text+                   NanoVG.Internal.Transformation+                   NanoVG.Internal.Types+  if flag(gles3)+    exposed-modules:+                     NanoVG.Internal.GLES3+  else+    if flag(gl2)+      exposed-modules:                        NanoVG.Internal.GL2-                       NanoVG.Internal.GLES3-                       NanoVG.Internal.Image-                       NanoVG.Internal.Paint-                       NanoVG.Internal.Path-                       NanoVG.Internal.Scissor-                       NanoVG.Internal.State-                       NanoVG.Internal.Style-                       NanoVG.Internal.Text-                       NanoVG.Internal.Transformation-                       NanoVG.Internal.Types+    else+      exposed-modules:+                       NanoVG.Internal.GL3   build-depends:       base >= 4.8 && <5.0                      , bytestring >= 0.10 && < 0.11-                     , containers >= 0.5 && < 0.6+                     , containers >= 0.5 && < 0.7                      , text >= 1.2 && < 1.3                      , vector >= 0.11 && < 0.13   hs-source-dirs:      src@@ -73,13 +82,13 @@   c-sources:           nanovg/src/nanovg.c                        cbits/nanovg_wrapper.c                        cbits/nanovg_gl.c-  cc-options:          -DNDEBUG+  cc-options:          -DNDEBUG -DFONS_USE_FREETYPE   ghc-options:         -Wall   if os(osx)     frameworks:          OpenGL     cc-options:          -Ddarwin_HOST_OS   else-    extra-libraries:     GLU, GL, m, GLEW+    extra-libraries:     GLU, GL, m, GLEW, X11, freetype     pkgconfig-depends: glew   if flag(gles3)     cpp-options:       -DGLES_3
nanovg/src/fontstash.h view
@@ -102,8 +102,8 @@ int fonsResetAtlas(FONScontext* stash, int width, int height);  // Add fonts-int fonsAddFont(FONScontext* s, const char* name, const char* path);-int fonsAddFontMem(FONScontext* s, const char* name, unsigned char* data, int ndata, int freeData);+int fonsAddFont(FONScontext* s, const char* name, const char* path, int fontIndex);+int fonsAddFontMem(FONScontext* s, const char* name, unsigned char* data, int ndata, int freeData, int fontIndex); int fonsGetFontByName(FONScontext* s, const char* name);  // State handling@@ -162,18 +162,26 @@ int fons__tt_init(FONScontext *context) { 	FT_Error ftError;-        FONS_NOTUSED(context);+	FONS_NOTUSED(context); 	ftError = FT_Init_FreeType(&ftLibrary); 	return ftError == 0; } -int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize)+int fons__tt_done(FONScontext *context) { 	FT_Error ftError; 	FONS_NOTUSED(context);+	ftError = FT_Done_FreeType(ftLibrary);+	return ftError == 0;+} +int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize, int fontIndex)+{+	FT_Error ftError;+	FONS_NOTUSED(context);+ 	//font->font.userdata = stash;-	ftError = FT_New_Memory_Face(ftLibrary, (const FT_Byte*)data, dataSize, 0, &font->font);+	ftError = FT_New_Memory_Face(ftLibrary, (const FT_Byte*)data, dataSize, fontIndex, &font->font); 	return ftError == 0; } @@ -186,7 +194,7 @@  float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size) {-	return size / (font->font->ascender - font->font->descender);+	return size / font->font->units_per_EM; }  int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)@@ -202,9 +210,9 @@ 	FT_Fixed advFixed; 	FONS_NOTUSED(scale); -	ftError = FT_Set_Pixel_Sizes(font->font, 0, (FT_UInt)(size * (float)font->font->units_per_EM / (float)(font->font->ascender - font->font->descender)));+	ftError = FT_Set_Pixel_Sizes(font->font, 0, size); 	if (ftError) return 0;-	ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER);+	ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT); 	if (ftError) return 0; 	ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, &advFixed); 	if (ftError) return 0;@@ -223,7 +231,7 @@ { 	FT_GlyphSlot ftGlyph = font->font->glyph; 	int ftGlyphOffset = 0;-	int x, y;+	unsigned int x, y; 	FONS_NOTUSED(outWidth); 	FONS_NOTUSED(outHeight); 	FONS_NOTUSED(scaleX);@@ -264,13 +272,24 @@ 	return 1; } -int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize)+int fons__tt_done(FONScontext *context) {-	int stbError;+	FONS_NOTUSED(context);+	return 1;+}++int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize, int fontIndex)+{+	int offset, stbError; 	FONS_NOTUSED(dataSize);  	font->font.userdata = context;-	stbError = stbtt_InitFont(&font->font, data, 0);+	offset = stbtt_GetFontOffsetForIndex(data, fontIndex);+	if (offset == -1) {+		stbError = 0;+	} else {+		stbError = stbtt_InitFont(&font->font, data, offset);+	} 	return stbError; } @@ -281,7 +300,7 @@  float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size) {-	return stbtt_ScaleForPixelHeight(&font->font, size);+	return stbtt_ScaleForMappingEmToPixels(&font->font, size); }  int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)@@ -312,7 +331,7 @@ #endif  #ifndef FONS_SCRATCH_BUF_SIZE-#	define FONS_SCRATCH_BUF_SIZE 64000+#	define FONS_SCRATCH_BUF_SIZE 96000 #endif #ifndef FONS_HASH_LUT_SIZE #	define FONS_HASH_LUT_SIZE 256@@ -778,6 +797,17 @@ 	return 0; } +void fonsResetFallbackFont(FONScontext* stash, int base)+{+	int i;++	FONSfont* baseFont = stash->fonts[base];+	baseFont->nfallbacks = 0;+	baseFont->nglyphs = 0;+	for (i = 0; i < FONS_HASH_LUT_SIZE; i++)+		baseFont->lut[i] = -1;+}+ void fonsSetSize(FONScontext* stash, float size) { 	fons__getState(stash)->size = size;@@ -876,7 +906,7 @@ 	return FONS_INVALID; } -int fonsAddFont(FONScontext* stash, const char* name, const char* path)+int fonsAddFont(FONScontext* stash, const char* name, const char* path, int fontIndex) { 	FILE* fp = 0; 	int dataSize = 0;@@ -894,9 +924,9 @@ 	readed = fread(data, 1, dataSize, fp); 	fclose(fp); 	fp = 0;-	if (readed != dataSize) goto error;+	if (readed != (size_t)dataSize) goto error; -	return fonsAddFontMem(stash, name, data, dataSize, 1);+	return fonsAddFontMem(stash, name, data, dataSize, 1, fontIndex);  error: 	if (data) free(data);@@ -904,7 +934,7 @@ 	return FONS_INVALID; } -int fonsAddFontMem(FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData)+int fonsAddFontMem(FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData, int fontIndex) { 	int i, ascent, descent, fh, lineGap; 	FONSfont* font;@@ -929,15 +959,16 @@  	// Init font 	stash->nscratch = 0;-	if (!fons__tt_loadFont(stash, &font->font, data, dataSize)) goto error;+	if (!fons__tt_loadFont(stash, &font->font, data, dataSize, fontIndex)) goto error;  	// Store normalized line height. The real line height is got 	// by multiplying the lineh by font size. 	fons__tt_getFontVMetrics( &font->font, &ascent, &descent, &lineGap);+	ascent += lineGap; 	fh = ascent - descent; 	font->ascender = (float)ascent / (float)fh; 	font->descender = (float)descent / (float)fh;-	font->lineh = (float)(fh + lineGap) / (float)fh;+	font->lineh = font->ascender - font->descender;  	return idx; @@ -1194,8 +1225,8 @@ 	y1 = (float)(glyph->y1-1);  	if (stash->params.flags & FONS_ZERO_TOPLEFT) {-		rx = (float)(int)(*x + xoff);-		ry = (float)(int)(*y + yoff);+		rx = floorf(*x + xoff);+		ry = floorf(*y + yoff);  		q->x0 = rx; 		q->y0 = ry;@@ -1207,8 +1238,8 @@ 		q->s1 = x1 * stash->itw; 		q->t1 = y1 * stash->ith; 	} else {-		rx = (float)(int)(*x + xoff);-		ry = (float)(int)(*y - yoff);+		rx = floorf(*x + xoff);+		ry = floorf(*y - yoff);  		q->x0 = rx; 		q->y0 = ry;@@ -1630,6 +1661,7 @@ 	if (stash->texData) free(stash->texData); 	if (stash->scratch) free(stash->scratch); 	free(stash);+	fons__tt_done(stash); }  void fonsSetErrorCallback(FONScontext* stash, void (*callback)(void* uptr, int error, int val), void* uptr)
nanovg/src/nanovg.c view
@@ -24,8 +24,11 @@ #include "nanovg.h" #define FONTSTASH_IMPLEMENTATION #include "fontstash.h"++#ifndef NVG_NO_STB #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h"+#endif   #ifdef _MSC_VER #pragma warning(disable: 4100)  // unreferenced formal parameter@@ -363,7 +366,7 @@ 	free(ctx); } -void nvgBeginFrame(NVGcontext* ctx, int windowWidth, int windowHeight, float devicePixelRatio)+void nvgBeginFrame(NVGcontext* ctx, float windowWidth, float windowHeight, float devicePixelRatio) { /*	printf("Tris: draws:%d  fill:%d  stroke:%d  text:%d  TOT:%d\n", 		ctx->drawCallCount, ctx->fillTriCount, ctx->strokeTriCount, ctx->textTriCount,@@ -788,6 +791,7 @@ 	nvgTransformMultiply(state->fill.xform, state->xform); } +#ifndef NVG_NO_STB int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags) { 	int w, h, n, image;@@ -816,6 +820,7 @@ 	stbi_image_free(img); 	return image; }+#endif  int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data) {@@ -1440,7 +1445,8 @@ }  static NVGvertex* nvg__roundJoin(NVGvertex* dst, NVGpoint* p0, NVGpoint* p1,-										float lw, float rw, float lu, float ru, int ncap, float fringe)+								 float lw, float rw, float lu, float ru, int ncap,+								 float fringe) { 	int i, n; 	float dlx0 = p0->dy;@@ -1573,36 +1579,39 @@ }  static NVGvertex* nvg__buttCapStart(NVGvertex* dst, NVGpoint* p,-										   float dx, float dy, float w, float d, float aa)+									float dx, float dy, float w, float d,+									float aa, float u0, float u1) { 	float px = p->x - dx*d; 	float py = p->y - dy*d; 	float dlx = dy; 	float dly = -dx;-	nvg__vset(dst, px + dlx*w - dx*aa, py + dly*w - dy*aa, 0,0); dst++;-	nvg__vset(dst, px - dlx*w - dx*aa, py - dly*w - dy*aa, 1,0); dst++;-	nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++;-	nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++;+	nvg__vset(dst, px + dlx*w - dx*aa, py + dly*w - dy*aa, u0,0); dst++;+	nvg__vset(dst, px - dlx*w - dx*aa, py - dly*w - dy*aa, u1,0); dst++;+	nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;+	nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++; 	return dst; }  static NVGvertex* nvg__buttCapEnd(NVGvertex* dst, NVGpoint* p,-										   float dx, float dy, float w, float d, float aa)+								  float dx, float dy, float w, float d,+								  float aa, float u0, float u1) { 	float px = p->x + dx*d; 	float py = p->y + dy*d; 	float dlx = dy; 	float dly = -dx;-	nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++;-	nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++;-	nvg__vset(dst, px + dlx*w + dx*aa, py + dly*w + dy*aa, 0,0); dst++;-	nvg__vset(dst, px - dlx*w + dx*aa, py - dly*w + dy*aa, 1,0); dst++;+	nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;+	nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++;+	nvg__vset(dst, px + dlx*w + dx*aa, py + dly*w + dy*aa, u0,0); dst++;+	nvg__vset(dst, px - dlx*w + dx*aa, py - dly*w + dy*aa, u1,0); dst++; 	return dst; }   static NVGvertex* nvg__roundCapStart(NVGvertex* dst, NVGpoint* p,-											float dx, float dy, float w, int ncap, float aa)+									 float dx, float dy, float w, int ncap,+									 float aa, float u0, float u1) { 	int i; 	float px = p->x;@@ -1613,16 +1622,17 @@ 	for (i = 0; i < ncap; i++) { 		float a = i/(float)(ncap-1)*NVG_PI; 		float ax = cosf(a) * w, ay = sinf(a) * w;-		nvg__vset(dst, px - dlx*ax - dx*ay, py - dly*ax - dy*ay, 0,1); dst++;+		nvg__vset(dst, px - dlx*ax - dx*ay, py - dly*ax - dy*ay, u0,1); dst++; 		nvg__vset(dst, px, py, 0.5f,1); dst++; 	}-	nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++;-	nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++;+	nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;+	nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++; 	return dst; }  static NVGvertex* nvg__roundCapEnd(NVGvertex* dst, NVGpoint* p,-										  float dx, float dy, float w, int ncap, float aa)+								   float dx, float dy, float w, int ncap,+								   float aa, float u0, float u1) { 	int i; 	float px = p->x;@@ -1630,13 +1640,13 @@ 	float dlx = dy; 	float dly = -dx; 	NVG_NOTUSED(aa);-	nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++;-	nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++;+	nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;+	nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++; 	for (i = 0; i < ncap; i++) { 		float a = i/(float)(ncap-1)*NVG_PI; 		float ax = cosf(a) * w, ay = sinf(a) * w; 		nvg__vset(dst, px, py, 0.5f,1); dst++;-		nvg__vset(dst, px - dlx*ax + dx*ay, py - dly*ax + dy*ay, 0,1); dst++;+		nvg__vset(dst, px - dlx*ax + dx*ay, py - dly*ax + dy*ay, u0,1); dst++; 	} 	return dst; }@@ -1712,15 +1722,24 @@ }  -static int nvg__expandStroke(NVGcontext* ctx, float w, int lineCap, int lineJoin, float miterLimit)+static int nvg__expandStroke(NVGcontext* ctx, float w, float fringe, int lineCap, int lineJoin, float miterLimit) { 	NVGpathCache* cache = ctx->cache; 	NVGvertex* verts; 	NVGvertex* dst; 	int cverts, i, j;-	float aa = ctx->fringeWidth;+	float aa = fringe;//ctx->fringeWidth;+	float u0 = 0.0f, u1 = 1.0f; 	int ncap = nvg__curveDivs(w, NVG_PI, ctx->tessTol);	// Calculate divisions per half circle. +	w += aa * 0.5f;++	// Disable the gradient used for antialiasing when antialiasing is not used.+	if (aa == 0.0f) {+		u0 = 0.5f;+		u1 = 0.5f;+	}+ 	nvg__calculateJoins(ctx, w, lineJoin, miterLimit);  	// Calculate max vertex usage.@@ -1781,42 +1800,42 @@ 			dy = p1->y - p0->y; 			nvg__normalize(&dx, &dy); 			if (lineCap == NVG_BUTT)-				dst = nvg__buttCapStart(dst, p0, dx, dy, w, -aa*0.5f, aa);+				dst = nvg__buttCapStart(dst, p0, dx, dy, w, -aa*0.5f, aa, u0, u1); 			else if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE)-				dst = nvg__buttCapStart(dst, p0, dx, dy, w, w-aa, aa);+				dst = nvg__buttCapStart(dst, p0, dx, dy, w, w-aa, aa, u0, u1); 			else if (lineCap == NVG_ROUND)-				dst = nvg__roundCapStart(dst, p0, dx, dy, w, ncap, aa);+				dst = nvg__roundCapStart(dst, p0, dx, dy, w, ncap, aa, u0, u1); 		}  		for (j = s; j < e; ++j) { 			if ((p1->flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) != 0) { 				if (lineJoin == NVG_ROUND) {-					dst = nvg__roundJoin(dst, p0, p1, w, w, 0, 1, ncap, aa);+					dst = nvg__roundJoin(dst, p0, p1, w, w, u0, u1, ncap, aa); 				} else {-					dst = nvg__bevelJoin(dst, p0, p1, w, w, 0, 1, aa);+					dst = nvg__bevelJoin(dst, p0, p1, w, w, u0, u1, aa); 				} 			} else {-				nvg__vset(dst, p1->x + (p1->dmx * w), p1->y + (p1->dmy * w), 0,1); dst++;-				nvg__vset(dst, p1->x - (p1->dmx * w), p1->y - (p1->dmy * w), 1,1); dst++;+				nvg__vset(dst, p1->x + (p1->dmx * w), p1->y + (p1->dmy * w), u0,1); dst++;+				nvg__vset(dst, p1->x - (p1->dmx * w), p1->y - (p1->dmy * w), u1,1); dst++; 			} 			p0 = p1++; 		}  		if (loop) { 			// Loop it-			nvg__vset(dst, verts[0].x, verts[0].y, 0,1); dst++;-			nvg__vset(dst, verts[1].x, verts[1].y, 1,1); dst++;+			nvg__vset(dst, verts[0].x, verts[0].y, u0,1); dst++;+			nvg__vset(dst, verts[1].x, verts[1].y, u1,1); dst++; 		} else { 			// Add cap 			dx = p1->x - p0->x; 			dy = p1->y - p0->y; 			nvg__normalize(&dx, &dy); 			if (lineCap == NVG_BUTT)-				dst = nvg__buttCapEnd(dst, p1, dx, dy, w, -aa*0.5f, aa);+				dst = nvg__buttCapEnd(dst, p1, dx, dy, w, -aa*0.5f, aa, u0, u1); 			else if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE)-				dst = nvg__buttCapEnd(dst, p1, dx, dy, w, w-aa, aa);+				dst = nvg__buttCapEnd(dst, p1, dx, dy, w, w-aa, aa, u0, u1); 			else if (lineCap == NVG_ROUND)-				dst = nvg__roundCapEnd(dst, p1, dx, dy, w, ncap, aa);+				dst = nvg__roundCapEnd(dst, p1, dx, dy, w, ncap, aa, u0, u1); 		}  		path->nstroke = (int)(dst - verts);@@ -2240,6 +2259,7 @@ 	const NVGpath* path; 	int i; + 	if (strokeWidth < ctx->fringeWidth) { 		// If the stroke width is less than pixel size, use alpha to emulate coverage. 		// Since coverage is area, scale by alpha*alpha.@@ -2256,9 +2276,9 @@ 	nvg__flattenPaths(ctx);  	if (ctx->params.edgeAntiAlias && state->shapeAntiAlias)-		nvg__expandStroke(ctx, strokeWidth*0.5f + ctx->fringeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit);+		nvg__expandStroke(ctx, strokeWidth*0.5f, ctx->fringeWidth, state->lineCap, state->lineJoin, state->miterLimit); 	else-		nvg__expandStroke(ctx, strokeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit);+		nvg__expandStroke(ctx, strokeWidth*0.5f, 0.0f, state->lineCap, state->lineJoin, state->miterLimit);  	ctx->params.renderStroke(ctx->params.userPtr, &strokePaint, state->compositeOperation, &state->scissor, ctx->fringeWidth, 							 strokeWidth, ctx->cache->paths, ctx->cache->npaths);@@ -2272,16 +2292,26 @@ }  // Add fonts-int nvgCreateFont(NVGcontext* ctx, const char* name, const char* path)+int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename) {-	return fonsAddFont(ctx->fs, name, path);+	return fonsAddFont(ctx->fs, name, filename, 0); } +int nvgCreateFontAtIndex(NVGcontext* ctx, const char* name, const char* filename, const int fontIndex)+{+	return fonsAddFont(ctx->fs, name, filename, fontIndex);+}+ int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData) {-	return fonsAddFontMem(ctx->fs, name, data, ndata, freeData);+	return fonsAddFontMem(ctx->fs, name, data, ndata, freeData, 0); } +int nvgCreateFontMemAtIndex(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData, const int fontIndex)+{+	return fonsAddFontMem(ctx->fs, name, data, ndata, freeData, fontIndex);+}+ int nvgFindFont(NVGcontext* ctx, const char* name) { 	if (name == NULL) return -1;@@ -2300,6 +2330,16 @@ 	return nvgAddFallbackFontId(ctx, nvgFindFont(ctx, baseFont), nvgFindFont(ctx, fallbackFont)); } +void nvgResetFallbackFontsId(NVGcontext* ctx, int baseFont)+{+	fonsResetFallbackFont(ctx->fs, baseFont);+}++void nvgResetFallbackFonts(NVGcontext* ctx, const char* baseFont)+{+	nvgResetFallbackFontsId(ctx, nvgFindFont(ctx, baseFont));+}+ // State setting void nvgFontSize(NVGcontext* ctx, float size) {@@ -2408,12 +2448,18 @@ 	paint.innerColor.a *= state->alpha; 	paint.outerColor.a *= state->alpha; -	ctx->params.renderTriangles(ctx->params.userPtr, &paint, state->compositeOperation, &state->scissor, verts, nverts);+	ctx->params.renderTriangles(ctx->params.userPtr, &paint, state->compositeOperation, &state->scissor, verts, nverts, ctx->fringeWidth);  	ctx->drawCallCount++; 	ctx->textTriCount += nverts/3; } +static int nvg__isTransformFlipped(const float *xform)+{+	float det = xform[0] * xform[3] - xform[2] * xform[1];+	return( det < 0);+}+ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end) { 	NVGstate* state = nvg__getState(ctx);@@ -2424,6 +2470,7 @@ 	float invscale = 1.0f / scale; 	int cverts = 0; 	int nverts = 0;+	int isFlipped = nvg__isTransformFlipped(state->xform);  	if (end == NULL) 		end = string + strlen(string);@@ -2445,18 +2492,24 @@ 	while (fonsTextIterNext(ctx->fs, &iter, &q)) { 		float c[4*2]; 		if (iter.prevGlyphIndex == -1) { // can not retrieve glyph?-			if (!nvg__allocTextAtlas(ctx))-				break; // no memory :( 			if (nverts != 0) { 				nvg__renderText(ctx, verts, nverts); 				nverts = 0; 			}+			if (!nvg__allocTextAtlas(ctx))+				break; // no memory :( 			iter = prevIter; 			fonsTextIterNext(ctx->fs, &iter, &q); // try again 			if (iter.prevGlyphIndex == -1) // still can not find glyph? 				break; 		} 		prevIter = iter;+		if(isFlipped) {+			float tmp;++			tmp = q.y0; q.y0 = q.y1; q.y1 = tmp;+			tmp = q.t0; q.t0 = q.t1; q.t1 = tmp;+		} 		// Transform corners. 		nvgTransformPoint(&c[0],&c[1], state->xform, q.x0*invscale, q.y0*invscale); 		nvgTransformPoint(&c[2],&c[3], state->xform, q.x1*invscale, q.y0*invscale);@@ -2669,7 +2722,7 @@ 					rowStartX = iter.x; 					rowStart = iter.str; 					rowEnd = iter.next;-					rowWidth = iter.nextx - rowStartX; // q.x1 - rowStartX;+					rowWidth = iter.nextx - rowStartX; 					rowMinX = q.x0 - rowStartX; 					rowMaxX = q.x1 - rowStartX; 					wordStart = iter.str;@@ -2699,7 +2752,7 @@ 				if ((ptype == NVG_SPACE && (type == NVG_CHAR || type == NVG_CJK_CHAR)) || type == NVG_CJK_CHAR) { 					wordStart = iter.str; 					wordStartX = iter.x;-					wordMinX = q.x0 - rowStartX;+					wordMinX = q.x0; 				}  				// Break to new line when a character is beyond break width.@@ -2736,13 +2789,13 @@ 						nrows++; 						if (nrows >= maxRows) 							return nrows;+						// Update row 						rowStartX = wordStartX; 						rowStart = wordStart; 						rowEnd = iter.next; 						rowWidth = iter.nextx - rowStartX;-						rowMinX = wordMinX;+						rowMinX = wordMinX - rowStartX; 						rowMaxX = q.x1 - rowStartX;-						// No change to the word start 					} 					// Set null break point 					breakEnd = rowStart;
nanovg/src/nanovg.h view
@@ -152,7 +152,7 @@ // For example, GLFW returns two dimension for an opened window: window size and // frame buffer size. In that case you would set windowWidth/Height to the window size // devicePixelRatio to: frameBufferWidth / windowWidth.-void nvgBeginFrame(NVGcontext* ctx, int windowWidth, int windowHeight, float devicePixelRatio);+void nvgBeginFrame(NVGcontext* ctx, float windowWidth, float windowHeight, float devicePixelRatio);  // Cancels drawing the current frame. void nvgCancelFrame(NVGcontext* ctx);@@ -414,7 +414,7 @@ NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float outr, 						   NVGcolor icol, NVGcolor ocol); -// Creates and returns an image patter. Parameters (ox,oy) specify the left-top location of the image pattern,+// Creates and returns an image pattern. Parameters (ox,oy) specify the left-top location of the image pattern, // (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render. // The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey,@@ -546,10 +546,16 @@ // Returns handle to the font. int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename); +// fontIndex specifies which font face to load from a .ttf/.ttc file.+int nvgCreateFontAtIndex(NVGcontext* ctx, const char* name, const char* filename, const int fontIndex);+ // Creates font by loading it from the specified memory chunk. // Returns handle to the font. int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData); +// fontIndex specifies which font face to load from a .ttf/.ttc file.+int nvgCreateFontMemAtIndex(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData, const int fontIndex);+ // Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found. int nvgFindFont(NVGcontext* ctx, const char* name); @@ -559,6 +565,12 @@ // Adds a fallback font by name. int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont); +// Resets fallback fonts by handle.+void nvgResetFallbackFontsId(NVGcontext* ctx, int baseFont);++// Resets fallback fonts by name.+void nvgResetFallbackFonts(NVGcontext* ctx, const char* baseFont);+ // Sets the font size of current text style. void nvgFontSize(NVGcontext* ctx, float size); @@ -653,12 +665,12 @@ 	int (*renderDeleteTexture)(void* uptr, int image); 	int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data); 	int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h);-	void (*renderViewport)(void* uptr, int width, int height, float devicePixelRatio);+	void (*renderViewport)(void* uptr, float width, float height, float devicePixelRatio); 	void (*renderCancel)(void* uptr); 	void (*renderFlush)(void* uptr); 	void (*renderFill)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths); 	void (*renderStroke)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths);-	void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, const NVGvertex* verts, int nverts);+	void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, const NVGvertex* verts, int nverts, float fringe); 	void (*renderDelete)(void* uptr); }; typedef struct NVGparams NVGparams;
nanovg/src/nanovg_gl.h view
@@ -268,6 +268,8 @@ 	GLuint stencilFuncMask; 	GLNVGblend blendFunc; 	#endif++	int dummyTex; }; typedef struct GLNVGcontext GLNVGcontext; @@ -500,6 +502,8 @@ #endif } +static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data);+ static int glnvg__renderCreate(void* uptr) { 	GLNVGcontext* gl = (GLNVGcontext*)uptr;@@ -700,6 +704,10 @@ #endif 	gl->fragSize = sizeof(GLNVGfragUniforms) + align - sizeof(GLNVGfragUniforms) % align; +	// Some platforms does not allow to have samples to unset textures.+	// Create empty one which is bound when there's no texture specified.+	gl->dummyTex = glnvg__renderCreateTexture(gl, NVG_TEXTURE_ALPHA, 1, 1, 0, NULL);+ 	glnvg__checkError(gl, "create done");  	glFinish();@@ -754,7 +762,7 @@ 	if (type == NVG_TEXTURE_RGBA) 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 	else-#if defined(NANOVG_GLES2)+#if defined(NANOVG_GLES2) || defined (NANOVG_GL2) 		glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); #elif defined(NANOVG_GLES3) 		glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data);@@ -846,7 +854,7 @@ 	if (tex->type == NVG_TEXTURE_RGBA) 		glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data); 	else-#ifdef NANOVG_GLES2+#if defined(NANOVG_GLES2) || defined(NANOVG_GL2) 		glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); #else 		glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RED, GL_UNSIGNED_BYTE, data);@@ -973,6 +981,7 @@  static void glnvg__setUniforms(GLNVGcontext* gl, int uniformOffset, int image) {+	GLNVGtexture* tex = NULL; #if NANOVG_GL_USE_UNIFORMBUFFER 	glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_FRAG_BINDING, gl->fragBuf, uniformOffset, sizeof(GLNVGfragUniforms)); #else@@ -981,20 +990,22 @@ #endif  	if (image != 0) {-		GLNVGtexture* tex = glnvg__findTexture(gl, image);-		glnvg__bindTexture(gl, tex != NULL ? tex->tex : 0);-		glnvg__checkError(gl, "tex paint tex");-	} else {-		glnvg__bindTexture(gl, 0);+		tex = glnvg__findTexture(gl, image); 	}+	// If no image is set, use empty texture+	if (tex == NULL) {+		tex = glnvg__findTexture(gl, gl->dummyTex);+	}+	glnvg__bindTexture(gl, tex != NULL ? tex->tex : 0);+	glnvg__checkError(gl, "tex paint tex"); } -static void glnvg__renderViewport(void* uptr, int width, int height, float devicePixelRatio)+static void glnvg__renderViewport(void* uptr, float width, float height, float devicePixelRatio) { 	NVG_NOTUSED(devicePixelRatio); 	GLNVGcontext* gl = (GLNVGcontext*)uptr;-	gl->view[0] = (float)width;-	gl->view[1] = (float)height;+	gl->view[0] = width;+	gl->view[1] = height; }  static void glnvg__fill(GLNVGcontext* gl, GLNVGcall* call)@@ -1049,12 +1060,12 @@ 	glnvg__setUniforms(gl, call->uniformOffset, call->image); 	glnvg__checkError(gl, "convex fill"); -	for (i = 0; i < npaths; i++)+	for (i = 0; i < npaths; i++) { 		glDrawArrays(GL_TRIANGLE_FAN, paths[i].fillOffset, paths[i].fillCount);-	if (gl->flags & NVG_ANTIALIAS) { 		// Draw fringes-		for (i = 0; i < npaths; i++)+		if (paths[i].strokeCount > 0) { 			glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount);+		} 	} } @@ -1481,7 +1492,7 @@ }  static void glnvg__renderTriangles(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor,-								   const NVGvertex* verts, int nverts)+								   const NVGvertex* verts, int nverts, float fringe) { 	GLNVGcontext* gl = (GLNVGcontext*)uptr; 	GLNVGcall* call = glnvg__allocCall(gl);@@ -1504,7 +1515,7 @@ 	call->uniformOffset = glnvg__allocFragUniforms(gl, 1); 	if (call->uniformOffset == -1) goto error; 	frag = nvg__fragUniformPtr(gl, call->uniformOffset);-	glnvg__convertPaint(gl, frag, paint, scissor, 1.0f, 1.0f, -1.0f);+	glnvg__convertPaint(gl, frag, paint, scissor, 1.0f, fringe, -1.0f); 	frag->type = NSVG_SHADER_IMG;  	return;
nanovg/src/stb_truetype.h view
@@ -1,3249 +1,5011 @@-// stb_truetype.h - v1.09 - public domain-// authored from 2009-2015 by Sean Barrett / RAD Game Tools-//-//   This library processes TrueType files:-//        parse files-//        extract glyph metrics-//        extract glyph shapes-//        render glyphs to one-channel bitmaps with antialiasing (box filter)-//-//   Todo:-//        non-MS cmaps-//        crashproof on bad data-//        hinting? (no longer patented)-//        cleartype-style AA?-//        optimize: use simple memory allocator for intermediates-//        optimize: build edge-list directly from curves-//        optimize: rasterize directly from curves?-//-// ADDITIONAL CONTRIBUTORS-//-//   Mikko Mononen: compound shape support, more cmap formats-//   Tor Andersson: kerning, subpixel rendering-//-//   Bug/warning reports/fixes:-//       "Zer" on mollyrocket (with fix)-//       Cass Everitt-//       stoiko (Haemimont Games)-//       Brian Hook -//       Walter van Niftrik-//       David Gow-//       David Given-//       Ivan-Assen Ivanov-//       Anthony Pesch-//       Johan Duparc-//       Hou Qiming-//       Fabian "ryg" Giesen-//       Martins Mozeiko-//       Cap Petschulat-//       Omar Cornut-//       github:aloucks-//       Peter LaValle-//       Sergey Popov-//       Giumo X. Clanjor-//       Higor Euripedes-//       Thomas Fields-//       Derek Vinyard-//-//   Misc other:-//       Ryan Gordon-//-// VERSION HISTORY-//-//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly-//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges-//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;-//                     variant PackFontRanges to pack and render in separate phases;-//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);-//                     fixed an assert() bug in the new rasterizer-//                     replace assert() with STBTT_assert() in new rasterizer-//   1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)-//                     also more precise AA rasterizer, except if shapes overlap-//                     remove need for STBTT_sort-//   1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC-//   1.04 (2015-04-15) typo in example-//   1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes-//-//   Full history can be found at the end of this file.-//-// LICENSE-//-//   This software is in the public domain. Where that dedication is not-//   recognized, you are granted a perpetual, irrevocable license to copy,-//   distribute, and modify this file as you see fit.-//-// USAGE-//-//   Include this file in whatever places neeed to refer to it. In ONE C/C++-//   file, write:-//      #define STB_TRUETYPE_IMPLEMENTATION-//   before the #include of this file. This expands out the actual-//   implementation into that C/C++ file.-//-//   To make the implementation private to the file that generates the implementation,-//      #define STBTT_STATIC-//-//   Simple 3D API (don't ship this, but it's fine for tools and quick start)-//           stbtt_BakeFontBitmap()               -- bake a font to a bitmap for use as texture-//           stbtt_GetBakedQuad()                 -- compute quad to draw for a given char-//-//   Improved 3D API (more shippable):-//           #include "stb_rect_pack.h"           -- optional, but you really want it-//           stbtt_PackBegin()-//           stbtt_PackSetOversample()            -- for improved quality on small fonts-//           stbtt_PackFontRanges()               -- pack and renders-//           stbtt_PackEnd()-//           stbtt_GetPackedQuad()-//-//   "Load" a font file from a memory buffer (you have to keep the buffer loaded)-//           stbtt_InitFont()-//           stbtt_GetFontOffsetForIndex()        -- use for TTC font collections-//-//   Render a unicode codepoint to a bitmap-//           stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap-//           stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide-//           stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be-//-//   Character advance/positioning-//           stbtt_GetCodepointHMetrics()-//           stbtt_GetFontVMetrics()-//           stbtt_GetCodepointKernAdvance()-//-//   Starting with version 1.06, the rasterizer was replaced with a new,-//   faster and generally-more-precise rasterizer. The new rasterizer more-//   accurately measures pixel coverage for anti-aliasing, except in the case-//   where multiple shapes overlap, in which case it overestimates the AA pixel-//   coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If-//   this turns out to be a problem, you can re-enable the old rasterizer with-//        #define STBTT_RASTERIZER_VERSION 1-//   which will incur about a 15% speed hit.-//-// ADDITIONAL DOCUMENTATION-//-//   Immediately after this block comment are a series of sample programs.-//-//   After the sample programs is the "header file" section. This section-//   includes documentation for each API function.-//-//   Some important concepts to understand to use this library:-//-//      Codepoint-//         Characters are defined by unicode codepoints, e.g. 65 is-//         uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is-//         the hiragana for "ma".-//-//      Glyph-//         A visual character shape (every codepoint is rendered as-//         some glyph)-//-//      Glyph index-//         A font-specific integer ID representing a glyph-//-//      Baseline-//         Glyph shapes are defined relative to a baseline, which is the-//         bottom of uppercase characters. Characters extend both above-//         and below the baseline.-//-//      Current Point-//         As you draw text to the screen, you keep track of a "current point"-//         which is the origin of each character. The current point's vertical-//         position is the baseline. Even "baked fonts" use this model.-//-//      Vertical Font Metrics-//         The vertical qualities of the font, used to vertically position-//         and space the characters. See docs for stbtt_GetFontVMetrics.-//-//      Font Size in Pixels or Points-//         The preferred interface for specifying font sizes in stb_truetype-//         is to specify how tall the font's vertical extent should be in pixels.-//         If that sounds good enough, skip the next paragraph.-//-//         Most font APIs instead use "points", which are a common typographic-//         measurement for describing font size, defined as 72 points per inch.-//         stb_truetype provides a point API for compatibility. However, true-//         "per inch" conventions don't make much sense on computer displays-//         since they different monitors have different number of pixels per-//         inch. For example, Windows traditionally uses a convention that-//         there are 96 pixels per inch, thus making 'inch' measurements have-//         nothing to do with inches, and thus effectively defining a point to-//         be 1.333 pixels. Additionally, the TrueType font data provides-//         an explicit scale factor to scale a given font's glyphs to points,-//         but the author has observed that this scale factor is often wrong-//         for non-commercial fonts, thus making fonts scaled in points-//         according to the TrueType spec incoherently sized in practice.-//-// ADVANCED USAGE-//-//   Quality:-//-//    - Use the functions with Subpixel at the end to allow your characters-//      to have subpixel positioning. Since the font is anti-aliased, not-//      hinted, this is very import for quality. (This is not possible with-//      baked fonts.)-//-//    - Kerning is now supported, and if you're supporting subpixel rendering-//      then kerning is worth using to give your text a polished look.-//-//   Performance:-//-//    - Convert Unicode codepoints to glyph indexes and operate on the glyphs;-//      if you don't do this, stb_truetype is forced to do the conversion on-//      every call.-//-//    - There are a lot of memory allocations. We should modify it to take-//      a temp buffer and allocate from the temp buffer (without freeing),-//      should help performance a lot.-//-// NOTES-//-//   The system uses the raw data found in the .ttf file without changing it-//   and without building auxiliary data structures. This is a bit inefficient-//   on little-endian systems (the data is big-endian), but assuming you're-//   caching the bitmaps or glyph shapes this shouldn't be a big deal.-//-//   It appears to be very hard to programmatically determine what font a-//   given file is in a general way. I provide an API for this, but I don't-//   recommend it.-//-//-// SOURCE STATISTICS (based on v0.6c, 2050 LOC)-//-//   Documentation & header file        520 LOC  \___ 660 LOC documentation-//   Sample code                        140 LOC  /-//   Truetype parsing                   620 LOC  ---- 620 LOC TrueType-//   Software rasterization             240 LOC  \                           .-//   Curve tesselation                  120 LOC   \__ 550 LOC Bitmap creation-//   Bitmap management                  100 LOC   /-//   Baked bitmap interface              70 LOC  /-//   Font name matching & access        150 LOC  ---- 150 -//   C runtime library abstraction       60 LOC  ----  60-//-//-// PERFORMANCE MEASUREMENTS FOR 1.06:-//-//                      32-bit     64-bit-//   Previous release:  8.83 s     7.68 s-//   Pool allocations:  7.72 s     6.34 s-//   Inline sort     :  6.54 s     5.65 s-//   New rasterizer  :  5.63 s     5.00 s--//////////////////////////////////////////////////////////////////////////////-//////////////////////////////////////////////////////////////////////////////-////-////  SAMPLE PROGRAMS-////-//-//  Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless-//-#if 0-#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation-#include "stb_truetype.h"--unsigned char ttf_buffer[1<<20];-unsigned char temp_bitmap[512*512];--stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs-GLuint ftex;--void my_stbtt_initfont(void)-{-   fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));-   stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!-   // can free ttf_buffer at this point-   glGenTextures(1, &ftex);-   glBindTexture(GL_TEXTURE_2D, ftex);-   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);-   // can free temp_bitmap at this point-   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);-}--void my_stbtt_print(float x, float y, char *text)-{-   // assume orthographic projection with units = screen pixels, origin at top left-   glEnable(GL_TEXTURE_2D);-   glBindTexture(GL_TEXTURE_2D, ftex);-   glBegin(GL_QUADS);-   while (*text) {-      if (*text >= 32 && *text < 128) {-         stbtt_aligned_quad q;-         stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9-         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);-         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);-         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);-         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);-      }-      ++text;-   }-   glEnd();-}-#endif-//-//-//////////////////////////////////////////////////////////////////////////////-//-// Complete program (this compiles): get a single bitmap, print as ASCII art-//-#if 0-#include <stdio.h>-#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation-#include "stb_truetype.h"--char ttf_buffer[1<<25];--int main(int argc, char **argv)-{-   stbtt_fontinfo font;-   unsigned char *bitmap;-   int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);--   fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));--   stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));-   bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);--   for (j=0; j < h; ++j) {-      for (i=0; i < w; ++i)-         putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);-      putchar('\n');-   }-   return 0;-}-#endif -//-// Output:-//-//     .ii.-//    @@@@@@.-//   V@Mio@@o-//   :i.  V@V-//     :oM@@M-//   :@@@MM@M-//   @@o  o@M-//  :@@.  M@M-//   @@@o@@@@-//   :M@@V:@@.-//  -//////////////////////////////////////////////////////////////////////////////-// -// Complete program: print "Hello World!" banner, with bugs-//-#if 0-char buffer[24<<20];-unsigned char screen[20][79];--int main(int arg, char **argv)-{-   stbtt_fontinfo font;-   int i,j,ascent,baseline,ch=0;-   float scale, xpos=2; // leave a little padding in case the character extends left-   char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness--   fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));-   stbtt_InitFont(&font, buffer, 0);--   scale = stbtt_ScaleForPixelHeight(&font, 15);-   stbtt_GetFontVMetrics(&font, &ascent,0,0);-   baseline = (int) (ascent*scale);--   while (text[ch]) {-      int advance,lsb,x0,y0,x1,y1;-      float x_shift = xpos - (float) floor(xpos);-      stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);-      stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);-      stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);-      // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong-      // because this API is really for baking character bitmaps into textures. if you want to render-      // a sequence of characters, you really need to render each bitmap to a temp buffer, then-      // "alpha blend" that into the working buffer-      xpos += (advance * scale);-      if (text[ch+1])-         xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);-      ++ch;-   }--   for (j=0; j < 20; ++j) {-      for (i=0; i < 78; ++i)-         putchar(" .:ioVM@"[screen[j][i]>>5]);-      putchar('\n');-   }--   return 0;-}-#endif---//////////////////////////////////////////////////////////////////////////////-//////////////////////////////////////////////////////////////////////////////-////-////   INTEGRATION WITH YOUR CODEBASE-////-////   The following sections allow you to supply alternate definitions-////   of C library functions used by stb_truetype.--#ifdef STB_TRUETYPE_IMPLEMENTATION-   // #define your own (u)stbtt_int8/16/32 before including to override this-   #ifndef stbtt_uint8-   typedef unsigned char   stbtt_uint8;-   typedef signed   char   stbtt_int8;-   typedef unsigned short  stbtt_uint16;-   typedef signed   short  stbtt_int16;-   typedef unsigned int    stbtt_uint32;-   typedef signed   int    stbtt_int32;-   #endif--   typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];-   typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];--   // #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h-   #ifndef STBTT_ifloor-   #include <math.h>-   #define STBTT_ifloor(x)   ((int) floor(x))-   #define STBTT_iceil(x)    ((int) ceil(x))-   #endif--   #ifndef STBTT_sqrt-   #include <math.h>-   #define STBTT_sqrt(x)      sqrt(x)-   #endif--   // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h-   #ifndef STBTT_malloc-   #include <stdlib.h>-   #define STBTT_malloc(x,u)  ((void)(u),malloc(x))-   #define STBTT_free(x,u)    ((void)(u),free(x))-   #endif--   #ifndef STBTT_assert-   #include <assert.h>-   #define STBTT_assert(x)    assert(x)-   #endif--   #ifndef STBTT_strlen-   #include <string.h>-   #define STBTT_strlen(x)    strlen(x)-   #endif--   #ifndef STBTT_memcpy-   #include <memory.h>-   #define STBTT_memcpy       memcpy-   #define STBTT_memset       memset-   #endif-#endif--///////////////////////////////////////////////////////////////////////////////-///////////////////////////////////////////////////////////////////////////////-////-////   INTERFACE-////-////--#ifndef __STB_INCLUDE_STB_TRUETYPE_H__-#define __STB_INCLUDE_STB_TRUETYPE_H__--#ifdef STBTT_STATIC-#define STBTT_DEF static-#else-#define STBTT_DEF extern-#endif--#ifdef __cplusplus-extern "C" {-#endif--//////////////////////////////////////////////////////////////////////////////-//-// TEXTURE BAKING API-//-// If you use this API, you only have to call two functions ever.-//--typedef struct-{-   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap-   float xoff,yoff,xadvance;-} stbtt_bakedchar;--STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)-                                float pixel_height,                     // height of font in pixels-                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in-                                int first_char, int num_chars,          // characters to bake-                                stbtt_bakedchar *chardata);             // you allocate this, it's num_chars long-// if return is positive, the first unused row of the bitmap-// if return is negative, returns the negative of the number of characters that fit-// if return is 0, no characters fit and no rows were used-// This uses a very crappy packing.--typedef struct-{-   float x0,y0,s0,t0; // top-left-   float x1,y1,s1,t1; // bottom-right-} stbtt_aligned_quad;--STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph,  // same data as above-                               int char_index,             // character to display-                               float *xpos, float *ypos,   // pointers to current position in screen pixel space-                               stbtt_aligned_quad *q,      // output: quad to draw-                               int opengl_fillrule);       // true if opengl fill rule; false if DX9 or earlier-// Call GetBakedQuad with char_index = 'character - first_char', and it-// creates the quad you need to draw and advances the current position.-//-// The coordinate system used assumes y increases downwards.-//-// Characters will extend both above and below the current position;-// see discussion of "BASELINE" above.-//-// It's inefficient; you might want to c&p it and optimize it.----//////////////////////////////////////////////////////////////////////////////-//-// NEW TEXTURE BAKING API-//-// This provides options for packing multiple fonts into one atlas, not-// perfectly but better than nothing.--typedef struct-{-   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap-   float xoff,yoff,xadvance;-   float xoff2,yoff2;-} stbtt_packedchar;--typedef struct stbtt_pack_context stbtt_pack_context;-typedef struct stbtt_fontinfo stbtt_fontinfo;-#ifndef STB_RECT_PACK_VERSION-typedef struct stbrp_rect stbrp_rect;-#endif--STBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);-// Initializes a packing context stored in the passed-in stbtt_pack_context.-// Future calls using this context will pack characters into the bitmap passed-// in here: a 1-channel bitmap that is weight x height. stride_in_bytes is-// the distance from one row to the next (or 0 to mean they are packed tightly-// together). "padding" is the amount of padding to leave between each-// character (normally you want '1' for bitmaps you'll use as textures with-// bilinear filtering).-//-// Returns 0 on failure, 1 on success.--STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc);-// Cleans up the packing context and frees all memory.--#define STBTT_POINT_SIZE(x)   (-(x))--STBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,-                                int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);-// Creates character bitmaps from the font_index'th font found in fontdata (use-// font_index=0 if you don't know what that is). It creates num_chars_in_range-// bitmaps for characters with unicode values starting at first_unicode_char_in_range-// and increasing. Data for how to render them is stored in chardata_for_range;-// pass these to stbtt_GetPackedQuad to get back renderable quads.-//-// font_size is the full height of the character from ascender to descender,-// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed-// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()-// and pass that result as 'font_size':-//       ...,                  20 , ... // font max minus min y is 20 pixels tall-//       ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall--typedef struct-{-   float font_size;-   int first_unicode_codepoint_in_range;  // if non-zero, then the chars are continuous, and this is the first codepoint-   int *array_of_unicode_codepoints;       // if non-zero, then this is an array of unicode codepoints-   int num_chars;-   stbtt_packedchar *chardata_for_range; // output-   unsigned char h_oversample, v_oversample; // don't set these, they're used internally-} stbtt_pack_range;--STBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);-// Creates character bitmaps from multiple ranges of characters stored in-// ranges. This will usually create a better-packed bitmap than multiple-// calls to stbtt_PackFontRange. Note that you can call this multiple-// times within a single PackBegin/PackEnd.--STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);-// Oversampling a font increases the quality by allowing higher-quality subpixel-// positioning, and is especially valuable at smaller text sizes.-//-// This function sets the amount of oversampling for all following calls to-// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given-// pack context. The default (no oversampling) is achieved by h_oversample=1-// and v_oversample=1. The total number of pixels required is-// h_oversample*v_oversample larger than the default; for example, 2x2-// oversampling requires 4x the storage of 1x1. For best results, render-// oversampled textures with bilinear filtering. Look at the readme in-// stb/tests/oversample for information about oversampled fonts-//-// To use with PackFontRangesGather etc., you must set it before calls-// call to PackFontRangesGatherRects.--STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph,  // same data as above-                               int char_index,             // character to display-                               float *xpos, float *ypos,   // pointers to current position in screen pixel space-                               stbtt_aligned_quad *q,      // output: quad to draw-                               int align_to_integer);--STBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);-STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);-STBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);-// Calling these functions in sequence is roughly equivalent to calling-// stbtt_PackFontRanges(). If you more control over the packing of multiple-// fonts, or if you want to pack custom data into a font texture, take a look-// at the source to of stbtt_PackFontRanges() and create a custom version -// using these functions, e.g. call GatherRects multiple times,-// building up a single array of rects, then call PackRects once,-// then call RenderIntoRects repeatedly. This may result in a-// better packing than calling PackFontRanges multiple times-// (or it may not).--// this is an opaque structure that you shouldn't mess with which holds-// all the context needed from PackBegin to PackEnd.-struct stbtt_pack_context {-   void *user_allocator_context;-   void *pack_info;-   int   width;-   int   height;-   int   stride_in_bytes;-   int   padding;-   unsigned int   h_oversample, v_oversample;-   unsigned char *pixels;-   void  *nodes;-};--//////////////////////////////////////////////////////////////////////////////-//-// FONT LOADING-//-//--STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);-// Each .ttf/.ttc file may have more than one font. Each font has a sequential-// index number starting from 0. Call this function to get the font offset for-// a given index; it returns -1 if the index is out of range. A regular .ttf-// file will only define one font and it always be at offset 0, so it will-// return '0' for index 0, and -1 for all other indices. You can just skip-// this step if you know it's that kind of font.---// The following structure is defined publically so you can declare one on-// the stack or as a global or etc, but you should treat it as opaque.-typedef struct stbtt_fontinfo-{-   void           * userdata;-   unsigned char  * data;              // pointer to .ttf file-   int              fontstart;         // offset of start of font--   int numGlyphs;                     // number of glyphs, needed for range checking--   int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf-   int index_map;                     // a cmap mapping for our chosen character encoding-   int indexToLocFormat;              // format needed to map from glyph index to glyph-} stbtt_fontinfo;--STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);-// Given an offset into the file that defines a font, this function builds-// the necessary cached info for the rest of the system. You must allocate-// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't-// need to do anything special to free it, because the contents are pure-// value data with no additional data structures. Returns 0 on failure.---//////////////////////////////////////////////////////////////////////////////-//-// CHARACTER TO GLYPH-INDEX CONVERSIOn--STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);-// If you're going to perform multiple operations on the same character-// and you want a speed-up, call this function with the character you're-// going to process, then use glyph-based functions instead of the-// codepoint-based functions.---//////////////////////////////////////////////////////////////////////////////-//-// CHARACTER PROPERTIES-//--STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);-// computes a scale factor to produce a font whose "height" is 'pixels' tall.-// Height is measured as the distance from the highest ascender to the lowest-// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics-// and computing:-//       scale = pixels / (ascent - descent)-// so if you prefer to measure height by the ascent only, use a similar calculation.--STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);-// computes a scale factor to produce a font whose EM size is mapped to-// 'pixels' tall. This is probably what traditional APIs compute, but-// I'm not positive.--STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);-// ascent is the coordinate above the baseline the font extends; descent-// is the coordinate below the baseline the font extends (i.e. it is typically negative)-// lineGap is the spacing between one row's descent and the next row's ascent...-// so you should advance the vertical position by "*ascent - *descent + *lineGap"-//   these are expressed in unscaled coordinates, so you must multiply by-//   the scale factor for a given size--STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);-// the bounding box around all possible characters--STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);-// leftSideBearing is the offset from the current horizontal position to the left edge of the character-// advanceWidth is the offset from the current horizontal position to the next horizontal position-//   these are expressed in unscaled coordinates--STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);-// an additional amount to add to the 'advance' value between ch1 and ch2--STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);-// Gets the bounding box of the visible part of the glyph, in unscaled coordinates--STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);-STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);-STBTT_DEF int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);-// as above, but takes one or more glyph indices for greater efficiency---//////////////////////////////////////////////////////////////////////////////-//-// GLYPH SHAPES (you probably don't need these, but they have to go before-// the bitmaps for C declaration-order reasons)-//--#ifndef STBTT_vmove // you can predefine these to use different values (but why?)-   enum {-      STBTT_vmove=1,-      STBTT_vline,-      STBTT_vcurve-   };-#endif--#ifndef stbtt_vertex // you can predefine this to use different values-                   // (we share this with other code at RAD)-   #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file-   typedef struct-   {-      stbtt_vertex_type x,y,cx,cy;-      unsigned char type,padding;-   } stbtt_vertex;-#endif--STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);-// returns non-zero if nothing is drawn for this glyph--STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);-STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);-// returns # of vertices and fills *vertices with the pointer to them-//   these are expressed in "unscaled" coordinates-//-// The shape is a series of countours. Each one starts with-// a STBTT_moveto, then consists of a series of mixed-// STBTT_lineto and STBTT_curveto segments. A lineto-// draws a line from previous endpoint to its x,y; a curveto-// draws a quadratic bezier from previous endpoint to-// its x,y, using cx,cy as the bezier control point.--STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);-// frees the data allocated above--//////////////////////////////////////////////////////////////////////////////-//-// BITMAP RENDERING-//--STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);-// frees the bitmap allocated below--STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);-// allocates a large-enough single-channel 8bpp bitmap and renders the-// specified character/glyph at the specified scale into it, with-// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).-// *width & *height are filled out with the width & height of the bitmap,-// which is stored left-to-right, top-to-bottom.-//-// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap--STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);-// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel-// shift for the character--STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);-// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap-// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap-// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the-// width and height and positioning info for it first.--STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);-// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel-// shift for the character--STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);-// get the bbox of the bitmap centered around the glyph origin; so the-// bitmap width is ix1-ix0, height is iy1-iy0, and location to place-// the bitmap top left is (leftSideBearing*scale,iy0).-// (Note that the bitmap uses y-increases-down, but the shape uses-// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)--STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);-// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel-// shift for the character--// the following functions are equivalent to the above functions, but operate-// on glyph indices instead of Unicode codepoints (for efficiency)-STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);-STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);-STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);-STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);-STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);-STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);---// @TODO: don't expose this structure-typedef struct-{-   int w,h,stride;-   unsigned char *pixels;-} stbtt__bitmap;--// rasterize a shape with quadratic beziers into a bitmap-STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result,        // 1-channel bitmap to draw into-                               float flatness_in_pixels,     // allowable error of curve in pixels-                               stbtt_vertex *vertices,       // array of vertices defining shape-                               int num_verts,                // number of vertices in above array-                               float scale_x, float scale_y, // scale applied to input vertices-                               float shift_x, float shift_y, // translation applied to input vertices-                               int x_off, int y_off,         // another translation applied to input-                               int invert,                   // if non-zero, vertically flip shape-                               void *userdata);              // context for to STBTT_MALLOC--//////////////////////////////////////////////////////////////////////////////-//-// Finding the right font...-//-// You should really just solve this offline, keep your own tables-// of what font is what, and don't try to get it out of the .ttf file.-// That's because getting it out of the .ttf file is really hard, because-// the names in the file can appear in many possible encodings, in many-// possible languages, and e.g. if you need a case-insensitive comparison,-// the details of that depend on the encoding & language in a complex way-// (actually underspecified in truetype, but also gigantic).-//-// But you can use the provided functions in two possible ways:-//     stbtt_FindMatchingFont() will use *case-sensitive* comparisons on-//             unicode-encoded names to try to find the font you want;-//             you can run this before calling stbtt_InitFont()-//-//     stbtt_GetFontNameString() lets you get any of the various strings-//             from the file yourself and do your own comparisons on them.-//             You have to have called stbtt_InitFont() first.---STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);-// returns the offset (not index) of the font that matches, or -1 if none-//   if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".-//   if you use any other flag, use a font name like "Arial"; this checks-//     the 'macStyle' header field; i don't know if fonts set this consistently-#define STBTT_MACSTYLE_DONTCARE     0-#define STBTT_MACSTYLE_BOLD         1-#define STBTT_MACSTYLE_ITALIC       2-#define STBTT_MACSTYLE_UNDERSCORE   4-#define STBTT_MACSTYLE_NONE         8   // <= not same as 0, this makes us check the bitfield is 0--STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);-// returns 1/0 whether the first string interpreted as utf8 is identical to-// the second string interpreted as big-endian utf16... useful for strings from next func--STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);-// returns the string (which may be big-endian double byte, e.g. for unicode)-// and puts the length in bytes in *length.-//-// some of the values for the IDs are below; for more see the truetype spec:-//     http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html-//     http://www.microsoft.com/typography/otspec/name.htm--enum { // platformID-   STBTT_PLATFORM_ID_UNICODE   =0,-   STBTT_PLATFORM_ID_MAC       =1,-   STBTT_PLATFORM_ID_ISO       =2,-   STBTT_PLATFORM_ID_MICROSOFT =3-};--enum { // encodingID for STBTT_PLATFORM_ID_UNICODE-   STBTT_UNICODE_EID_UNICODE_1_0    =0,-   STBTT_UNICODE_EID_UNICODE_1_1    =1,-   STBTT_UNICODE_EID_ISO_10646      =2,-   STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,-   STBTT_UNICODE_EID_UNICODE_2_0_FULL=4-};--enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT-   STBTT_MS_EID_SYMBOL        =0,-   STBTT_MS_EID_UNICODE_BMP   =1,-   STBTT_MS_EID_SHIFTJIS      =2,-   STBTT_MS_EID_UNICODE_FULL  =10-};--enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes-   STBTT_MAC_EID_ROMAN        =0,   STBTT_MAC_EID_ARABIC       =4,-   STBTT_MAC_EID_JAPANESE     =1,   STBTT_MAC_EID_HEBREW       =5,-   STBTT_MAC_EID_CHINESE_TRAD =2,   STBTT_MAC_EID_GREEK        =6,-   STBTT_MAC_EID_KOREAN       =3,   STBTT_MAC_EID_RUSSIAN      =7-};--enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...-       // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs-   STBTT_MS_LANG_ENGLISH     =0x0409,   STBTT_MS_LANG_ITALIAN     =0x0410,-   STBTT_MS_LANG_CHINESE     =0x0804,   STBTT_MS_LANG_JAPANESE    =0x0411,-   STBTT_MS_LANG_DUTCH       =0x0413,   STBTT_MS_LANG_KOREAN      =0x0412,-   STBTT_MS_LANG_FRENCH      =0x040c,   STBTT_MS_LANG_RUSSIAN     =0x0419,-   STBTT_MS_LANG_GERMAN      =0x0407,   STBTT_MS_LANG_SPANISH     =0x0409,-   STBTT_MS_LANG_HEBREW      =0x040d,   STBTT_MS_LANG_SWEDISH     =0x041D-};--enum { // languageID for STBTT_PLATFORM_ID_MAC-   STBTT_MAC_LANG_ENGLISH      =0 ,   STBTT_MAC_LANG_JAPANESE     =11,-   STBTT_MAC_LANG_ARABIC       =12,   STBTT_MAC_LANG_KOREAN       =23,-   STBTT_MAC_LANG_DUTCH        =4 ,   STBTT_MAC_LANG_RUSSIAN      =32,-   STBTT_MAC_LANG_FRENCH       =1 ,   STBTT_MAC_LANG_SPANISH      =6 ,-   STBTT_MAC_LANG_GERMAN       =2 ,   STBTT_MAC_LANG_SWEDISH      =5 ,-   STBTT_MAC_LANG_HEBREW       =10,   STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,-   STBTT_MAC_LANG_ITALIAN      =3 ,   STBTT_MAC_LANG_CHINESE_TRAD =19-};--#ifdef __cplusplus-}-#endif--#endif // __STB_INCLUDE_STB_TRUETYPE_H__--///////////////////////////////////////////////////////////////////////////////-///////////////////////////////////////////////////////////////////////////////-////-////   IMPLEMENTATION-////-////--#ifdef STB_TRUETYPE_IMPLEMENTATION--#ifndef STBTT_MAX_OVERSAMPLE-#define STBTT_MAX_OVERSAMPLE   8-#endif--#if STBTT_MAX_OVERSAMPLE > 255-#error "STBTT_MAX_OVERSAMPLE cannot be > 255"-#endif--typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];--#ifndef STBTT_RASTERIZER_VERSION-#define STBTT_RASTERIZER_VERSION 2-#endif--//////////////////////////////////////////////////////////////////////////-//-// accessors to parse data from file-//--// on platforms that don't allow misaligned reads, if we want to allow-// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE--#define ttBYTE(p)     (* (stbtt_uint8 *) (p))-#define ttCHAR(p)     (* (stbtt_int8 *) (p))-#define ttFixed(p)    ttLONG(p)--#if defined(STB_TRUETYPE_BIGENDIAN) && !defined(ALLOW_UNALIGNED_TRUETYPE)--   #define ttUSHORT(p)   (* (stbtt_uint16 *) (p))-   #define ttSHORT(p)    (* (stbtt_int16 *) (p))-   #define ttULONG(p)    (* (stbtt_uint32 *) (p))-   #define ttLONG(p)     (* (stbtt_int32 *) (p))--#else--   static stbtt_uint16 ttUSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; }-   static stbtt_int16 ttSHORT(const stbtt_uint8 *p)   { return p[0]*256 + p[1]; }-   static stbtt_uint32 ttULONG(const stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }-   static stbtt_int32 ttLONG(const stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }--#endif--#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))-#define stbtt_tag(p,str)           stbtt_tag4(p,str[0],str[1],str[2],str[3])--static int stbtt__isfont(const stbtt_uint8 *font)-{-   // check the version number-   if (stbtt_tag4(font, '1',0,0,0))  return 1; // TrueType 1-   if (stbtt_tag(font, "typ1"))   return 1; // TrueType with type 1 font -- we don't support this!-   if (stbtt_tag(font, "OTTO"))   return 1; // OpenType with CFF-   if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0-   return 0;-}--// @OPTIMIZE: binary search-static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)-{-   stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);-   stbtt_uint32 tabledir = fontstart + 12;-   stbtt_int32 i;-   for (i=0; i < num_tables; ++i) {-      stbtt_uint32 loc = tabledir + 16*i;-      if (stbtt_tag(data+loc+0, tag))-         return ttULONG(data+loc+8);-   }-   return 0;-}--STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *font_collection, int index)-{-   // if it's just a font, there's only one valid index-   if (stbtt__isfont(font_collection))-      return index == 0 ? 0 : -1;--   // check if it's a TTC-   if (stbtt_tag(font_collection, "ttcf")) {-      // version 1?-      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {-         stbtt_int32 n = ttLONG(font_collection+8);-         if (index >= n)-            return -1;-         return ttULONG(font_collection+12+index*4);-      }-   }-   return -1;-}--STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data2, int fontstart)-{-   stbtt_uint8 *data = (stbtt_uint8 *) data2;-   stbtt_uint32 cmap, t;-   stbtt_int32 i,numTables;--   info->data = data;-   info->fontstart = fontstart;--   cmap = stbtt__find_table(data, fontstart, "cmap");       // required-   info->loca = stbtt__find_table(data, fontstart, "loca"); // required-   info->head = stbtt__find_table(data, fontstart, "head"); // required-   info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required-   info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required-   info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required-   info->kern = stbtt__find_table(data, fontstart, "kern"); // not required-   if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx)-      return 0;--   t = stbtt__find_table(data, fontstart, "maxp");-   if (t)-      info->numGlyphs = ttUSHORT(data+t+4);-   else-      info->numGlyphs = 0xffff;--   // find a cmap encoding table we understand *now* to avoid searching-   // later. (todo: could make this installable)-   // the same regardless of glyph.-   numTables = ttUSHORT(data + cmap + 2);-   info->index_map = 0;-   for (i=0; i < numTables; ++i) {-      stbtt_uint32 encoding_record = cmap + 4 + 8 * i;-      // find an encoding we understand:-      switch(ttUSHORT(data+encoding_record)) {-         case STBTT_PLATFORM_ID_MICROSOFT:-            switch (ttUSHORT(data+encoding_record+2)) {-               case STBTT_MS_EID_UNICODE_BMP:-               case STBTT_MS_EID_UNICODE_FULL:-                  // MS/Unicode-                  info->index_map = cmap + ttULONG(data+encoding_record+4);-                  break;-            }-            break;-        case STBTT_PLATFORM_ID_UNICODE:-            // Mac/iOS has these-            // all the encodingIDs are unicode, so we don't bother to check it-            info->index_map = cmap + ttULONG(data+encoding_record+4);-            break;-      }-   }-   if (info->index_map == 0)-      return 0;--   info->indexToLocFormat = ttUSHORT(data+info->head + 50);-   return 1;-}--STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)-{-   stbtt_uint8 *data = info->data;-   stbtt_uint32 index_map = info->index_map;--   stbtt_uint16 format = ttUSHORT(data + index_map + 0);-   if (format == 0) { // apple byte encoding-      stbtt_int32 bytes = ttUSHORT(data + index_map + 2);-      if (unicode_codepoint < bytes-6)-         return ttBYTE(data + index_map + 6 + unicode_codepoint);-      return 0;-   } else if (format == 6) {-      stbtt_uint32 first = ttUSHORT(data + index_map + 6);-      stbtt_uint32 count = ttUSHORT(data + index_map + 8);-      if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)-         return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);-      return 0;-   } else if (format == 2) {-      STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean-      return 0;-   } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges-      stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;-      stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;-      stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);-      stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;--      // do a binary search of the segments-      stbtt_uint32 endCount = index_map + 14;-      stbtt_uint32 search = endCount;--      if (unicode_codepoint > 0xffff)-         return 0;--      // they lie from endCount .. endCount + segCount-      // but searchRange is the nearest power of two, so...-      if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))-         search += rangeShift*2;--      // now decrement to bias correctly to find smallest-      search -= 2;-      while (entrySelector) {-         stbtt_uint16 end;-         searchRange >>= 1;-         end = ttUSHORT(data + search + searchRange*2);-         if (unicode_codepoint > end)-            search += searchRange*2;-         --entrySelector;-      }-      search += 2;--      {-         stbtt_uint16 offset, start;-         stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);--         STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));-         start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);-         if (unicode_codepoint < start)-            return 0;--         offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);-         if (offset == 0)-            return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));--         return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);-      }-   } else if (format == 12 || format == 13) {-      stbtt_uint32 ngroups = ttULONG(data+index_map+12);-      stbtt_int32 low,high;-      low = 0; high = (stbtt_int32)ngroups;-      // Binary search the right group.-      while (low < high) {-         stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high-         stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);-         stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);-         if ((stbtt_uint32) unicode_codepoint < start_char)-            high = mid;-         else if ((stbtt_uint32) unicode_codepoint > end_char)-            low = mid+1;-         else {-            stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);-            if (format == 12)-               return start_glyph + unicode_codepoint-start_char;-            else // format == 13-               return start_glyph;-         }-      }-      return 0; // not found-   }-   // @TODO-   STBTT_assert(0);-   return 0;-}--STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)-{-   return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);-}--static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)-{-   v->type = type;-   v->x = (stbtt_int16) x;-   v->y = (stbtt_int16) y;-   v->cx = (stbtt_int16) cx;-   v->cy = (stbtt_int16) cy;-}--static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)-{-   int g1,g2;--   if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range-   if (info->indexToLocFormat >= 2)    return -1; // unknown index->glyph map format--   if (info->indexToLocFormat == 0) {-      g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;-      g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;-   } else {-      g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);-      g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);-   }--   return g1==g2 ? -1 : g1; // if length is 0, return -1-}--STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)-{-   int g = stbtt__GetGlyfOffset(info, glyph_index);-   if (g < 0) return 0;--   if (x0) *x0 = ttSHORT(info->data + g + 2);-   if (y0) *y0 = ttSHORT(info->data + g + 4);-   if (x1) *x1 = ttSHORT(info->data + g + 6);-   if (y1) *y1 = ttSHORT(info->data + g + 8);-   return 1;-}--STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)-{-   return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);-}--STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)-{-   stbtt_int16 numberOfContours;-   int g = stbtt__GetGlyfOffset(info, glyph_index);-   if (g < 0) return 1;-   numberOfContours = ttSHORT(info->data + g);-   return numberOfContours == 0;-}--static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,-    stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)-{-   if (start_off) {-      if (was_off)-         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);-      stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);-   } else {-      if (was_off)-         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);-      else-         stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);-   }-   return num_vertices;-}--STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)-{-   stbtt_int16 numberOfContours;-   stbtt_uint8 *endPtsOfContours;-   stbtt_uint8 *data = info->data;-   stbtt_vertex *vertices=0;-   int num_vertices=0;-   int g = stbtt__GetGlyfOffset(info, glyph_index);--   *pvertices = NULL;--   if (g < 0) return 0;--   numberOfContours = ttSHORT(data + g);--   if (numberOfContours > 0) {-      stbtt_uint8 flags=0,flagcount;-      stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;-      stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;-      stbtt_uint8 *points;-      endPtsOfContours = (data + g + 10);-      ins = ttUSHORT(data + g + 10 + numberOfContours * 2);-      points = data + g + 10 + numberOfContours * 2 + 2 + ins;--      n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);--      m = n + 2*numberOfContours;  // a loose bound on how many vertices we might need-      vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);-      if (vertices == 0)-         return 0;--      next_move = 0;-      flagcount=0;--      // in first pass, we load uninterpreted data into the allocated array-      // above, shifted to the end of the array so we won't overwrite it when-      // we create our final data starting from the front--      off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated--      // first load flags--      for (i=0; i < n; ++i) {-         if (flagcount == 0) {-            flags = *points++;-            if (flags & 8)-               flagcount = *points++;-         } else-            --flagcount;-         vertices[off+i].type = flags;-      }--      // now load x coordinates-      x=0;-      for (i=0; i < n; ++i) {-         flags = vertices[off+i].type;-         if (flags & 2) {-            stbtt_int16 dx = *points++;-            x += (flags & 16) ? dx : -dx; // ???-         } else {-            if (!(flags & 16)) {-               x = x + (stbtt_int16) (points[0]*256 + points[1]);-               points += 2;-            }-         }-         vertices[off+i].x = (stbtt_int16) x;-      }--      // now load y coordinates-      y=0;-      for (i=0; i < n; ++i) {-         flags = vertices[off+i].type;-         if (flags & 4) {-            stbtt_int16 dy = *points++;-            y += (flags & 32) ? dy : -dy; // ???-         } else {-            if (!(flags & 32)) {-               y = y + (stbtt_int16) (points[0]*256 + points[1]);-               points += 2;-            }-         }-         vertices[off+i].y = (stbtt_int16) y;-      }--      // now convert them to our format-      num_vertices=0;-      sx = sy = cx = cy = scx = scy = 0;-      for (i=0; i < n; ++i) {-         flags = vertices[off+i].type;-         x     = (stbtt_int16) vertices[off+i].x;-         y     = (stbtt_int16) vertices[off+i].y;--         if (next_move == i) {-            if (i != 0)-               num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);--            // now start the new one               -            start_off = !(flags & 1);-            if (start_off) {-               // if we start off with an off-curve point, then when we need to find a point on the curve-               // where we can start, and we need to save some state for when we wraparound.-               scx = x;-               scy = y;-               if (!(vertices[off+i+1].type & 1)) {-                  // next point is also a curve point, so interpolate an on-point curve-                  sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;-                  sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;-               } else {-                  // otherwise just use the next point as our start point-                  sx = (stbtt_int32) vertices[off+i+1].x;-                  sy = (stbtt_int32) vertices[off+i+1].y;-                  ++i; // we're using point i+1 as the starting point, so skip it-               }-            } else {-               sx = x;-               sy = y;-            }-            stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);-            was_off = 0;-            next_move = 1 + ttUSHORT(endPtsOfContours+j*2);-            ++j;-         } else {-            if (!(flags & 1)) { // if it's a curve-               if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint-                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);-               cx = x;-               cy = y;-               was_off = 1;-            } else {-               if (was_off)-                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);-               else-                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);-               was_off = 0;-            }-         }-      }-      num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);-   } else if (numberOfContours == -1) {-      // Compound shapes.-      int more = 1;-      stbtt_uint8 *comp = data + g + 10;-      num_vertices = 0;-      vertices = 0;-      while (more) {-         stbtt_uint16 flags, gidx;-         int comp_num_verts = 0, i;-         stbtt_vertex *comp_verts = 0, *tmp = 0;-         float mtx[6] = {1,0,0,1,0,0}, m, n;-         -         flags = ttSHORT(comp); comp+=2;-         gidx = ttSHORT(comp); comp+=2;--         if (flags & 2) { // XY values-            if (flags & 1) { // shorts-               mtx[4] = ttSHORT(comp); comp+=2;-               mtx[5] = ttSHORT(comp); comp+=2;-            } else {-               mtx[4] = ttCHAR(comp); comp+=1;-               mtx[5] = ttCHAR(comp); comp+=1;-            }-         }-         else {-            // @TODO handle matching point-            STBTT_assert(0);-         }-         if (flags & (1<<3)) { // WE_HAVE_A_SCALE-            mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;-            mtx[1] = mtx[2] = 0;-         } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE-            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;-            mtx[1] = mtx[2] = 0;-            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;-         } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO-            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;-            mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;-            mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;-            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;-         }-         -         // Find transformation scales.-         m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);-         n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);--         // Get indexed glyph.-         comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);-         if (comp_num_verts > 0) {-            // Transform vertices.-            for (i = 0; i < comp_num_verts; ++i) {-               stbtt_vertex* v = &comp_verts[i];-               stbtt_vertex_type x,y;-               x=v->x; y=v->y;-               v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));-               v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));-               x=v->cx; y=v->cy;-               v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));-               v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));-            }-            // Append vertices.-            tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);-            if (!tmp) {-               if (vertices) STBTT_free(vertices, info->userdata);-               if (comp_verts) STBTT_free(comp_verts, info->userdata);-               return 0;-            }-            if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));-            STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));-            if (vertices) STBTT_free(vertices, info->userdata);-            vertices = tmp;-            STBTT_free(comp_verts, info->userdata);-            num_vertices += comp_num_verts;-         }-         // More components ?-         more = flags & (1<<5);-      }-   } else if (numberOfContours < 0) {-      // @TODO other compound variations?-      STBTT_assert(0);-   } else {-      // numberOfCounters == 0, do nothing-   }--   *pvertices = vertices;-   return num_vertices;-}--STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)-{-   stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);-   if (glyph_index < numOfLongHorMetrics) {-      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*glyph_index);-      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);-   } else {-      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));-      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));-   }-}--STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)-{-   stbtt_uint8 *data = info->data + info->kern;-   stbtt_uint32 needle, straw;-   int l, r, m;--   // we only look at the first table. it must be 'horizontal' and format 0.-   if (!info->kern)-      return 0;-   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1-      return 0;-   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format-      return 0;--   l = 0;-   r = ttUSHORT(data+10) - 1;-   needle = glyph1 << 16 | glyph2;-   while (l <= r) {-      m = (l + r) >> 1;-      straw = ttULONG(data+18+(m*6)); // note: unaligned read-      if (needle < straw)-         r = m - 1;-      else if (needle > straw)-         l = m + 1;-      else-         return ttSHORT(data+22+(m*6));-   }-   return 0;-}--STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)-{-   if (!info->kern) // if no kerning table, don't waste time looking up both codepoint->glyphs-      return 0;-   return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));-}--STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)-{-   stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);-}--STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)-{-   if (ascent ) *ascent  = ttSHORT(info->data+info->hhea + 4);-   if (descent) *descent = ttSHORT(info->data+info->hhea + 6);-   if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);-}--STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)-{-   *x0 = ttSHORT(info->data + info->head + 36);-   *y0 = ttSHORT(info->data + info->head + 38);-   *x1 = ttSHORT(info->data + info->head + 40);-   *y1 = ttSHORT(info->data + info->head + 42);-}--STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)-{-   int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);-   return (float) height / fheight;-}--STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)-{-   int unitsPerEm = ttUSHORT(info->data + info->head + 18);-   return pixels / unitsPerEm;-}--STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)-{-   STBTT_free(v, info->userdata);-}--//////////////////////////////////////////////////////////////////////////////-//-// antialiasing software rasterizer-//--STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)-{-   int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning-   if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {-      // e.g. space character-      if (ix0) *ix0 = 0;-      if (iy0) *iy0 = 0;-      if (ix1) *ix1 = 0;-      if (iy1) *iy1 = 0;-   } else {-      // move to integral bboxes (treating pixels as little squares, what pixels get touched)?-      if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);-      if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);-      if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);-      if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);-   }-}--STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)-{-   stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);-}--STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)-{-   stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);-}--STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)-{-   stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);-}--//////////////////////////////////////////////////////////////////////////////-//-//  Rasterizer--typedef struct stbtt__hheap_chunk-{-   struct stbtt__hheap_chunk *next;-} stbtt__hheap_chunk;--typedef struct stbtt__hheap-{-   struct stbtt__hheap_chunk *head;-   void   *first_free;-   int    num_remaining_in_head_chunk;-} stbtt__hheap;--static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)-{-   if (hh->first_free) {-      void *p = hh->first_free;-      hh->first_free = * (void **) p;-      return p;-   } else {-      if (hh->num_remaining_in_head_chunk == 0) {-         int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);-         stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);-         if (c == NULL)-            return NULL;-         c->next = hh->head;-         hh->head = c;-         hh->num_remaining_in_head_chunk = count;-      }-      --hh->num_remaining_in_head_chunk;-      return (char *) (hh->head) + size * hh->num_remaining_in_head_chunk;-   }-}--static void stbtt__hheap_free(stbtt__hheap *hh, void *p)-{-   *(void **) p = hh->first_free;-   hh->first_free = p;-}--static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)-{-   stbtt__hheap_chunk *c = hh->head;-   while (c) {-      stbtt__hheap_chunk *n = c->next;-      STBTT_free(c, userdata);-      c = n;-   }-}--typedef struct stbtt__edge {-   float x0,y0, x1,y1;-   int invert;-} stbtt__edge;---typedef struct stbtt__active_edge-{-   struct stbtt__active_edge *next;-   #if STBTT_RASTERIZER_VERSION==1-   int x,dx;-   float ey;-   int direction;-   #elif STBTT_RASTERIZER_VERSION==2-   float fx,fdx,fdy;-   float direction;-   float sy;-   float ey;-   #else-   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"-   #endif-} stbtt__active_edge;--#if STBTT_RASTERIZER_VERSION == 1-#define STBTT_FIXSHIFT   10-#define STBTT_FIX        (1 << STBTT_FIXSHIFT)-#define STBTT_FIXMASK    (STBTT_FIX-1)--static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)-{-   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);-   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);-   STBTT_assert(z != NULL);-   if (!z) return z;-   -   // round dx down to avoid overshooting-   if (dxdy < 0)-      z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);-   else-      z->dx = STBTT_ifloor(STBTT_FIX * dxdy);--   z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount-   z->x -= off_x * STBTT_FIX;--   z->ey = e->y1;-   z->next = 0;-   z->direction = e->invert ? 1 : -1;-   return z;-}-#elif STBTT_RASTERIZER_VERSION == 2-static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)-{-   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);-   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);-   STBTT_assert(z != NULL);-   //STBTT_assert(e->y0 <= start_point);-   if (!z) return z;-   z->fdx = dxdy;-   z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;-   z->fx = e->x0 + dxdy * (start_point - e->y0);-   z->fx -= off_x;-   z->direction = e->invert ? 1.0f : -1.0f;-   z->sy = e->y0;-   z->ey = e->y1;-   z->next = 0;-   return z;-}-#else-#error "Unrecognized value of STBTT_RASTERIZER_VERSION"-#endif--#if STBTT_RASTERIZER_VERSION == 1-// note: this routine clips fills that extend off the edges... ideally this-// wouldn't happen, but it could happen if the truetype glyph bounding boxes-// are wrong, or if the user supplies a too-small bitmap-static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)-{-   // non-zero winding fill-   int x0=0, w=0;--   while (e) {-      if (w == 0) {-         // if we're currently at zero, we need to record the edge start point-         x0 = e->x; w += e->direction;-      } else {-         int x1 = e->x; w += e->direction;-         // if we went to zero, we need to draw-         if (w == 0) {-            int i = x0 >> STBTT_FIXSHIFT;-            int j = x1 >> STBTT_FIXSHIFT;--            if (i < len && j >= 0) {-               if (i == j) {-                  // x0,x1 are the same pixel, so compute combined coverage-                  scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);-               } else {-                  if (i >= 0) // add antialiasing for x0-                     scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);-                  else-                     i = -1; // clip--                  if (j < len) // add antialiasing for x1-                     scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);-                  else-                     j = len; // clip--                  for (++i; i < j; ++i) // fill pixels between x0 and x1-                     scanline[i] = scanline[i] + (stbtt_uint8) max_weight;-               }-            }-         }-      }-      -      e = e->next;-   }-}--static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)-{-   stbtt__hheap hh = { 0, 0, 0 };-   stbtt__active_edge *active = NULL;-   int y,j=0;-   int max_weight = (255 / vsubsample);  // weight per vertical scanline-   int s; // vertical subsample index-   unsigned char scanline_data[512], *scanline;--   if (result->w > 512)-      scanline = (unsigned char *) STBTT_malloc(result->w, userdata);-   else-      scanline = scanline_data;--   y = off_y * vsubsample;-   e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;--   while (j < result->h) {-      STBTT_memset(scanline, 0, result->w);-      for (s=0; s < vsubsample; ++s) {-         // find center of pixel for this scanline-         float scan_y = y + 0.5f;-         stbtt__active_edge **step = &active;--         // update all active edges;-         // remove all active edges that terminate before the center of this scanline-         while (*step) {-            stbtt__active_edge * z = *step;-            if (z->ey <= scan_y) {-               *step = z->next; // delete from list-               STBTT_assert(z->direction);-               z->direction = 0;-               stbtt__hheap_free(&hh, z);-            } else {-               z->x += z->dx; // advance to position for current scanline-               step = &((*step)->next); // advance through list-            }-         }--         // resort the list if needed-         for(;;) {-            int changed=0;-            step = &active;-            while (*step && (*step)->next) {-               if ((*step)->x > (*step)->next->x) {-                  stbtt__active_edge *t = *step;-                  stbtt__active_edge *q = t->next;--                  t->next = q->next;-                  q->next = t;-                  *step = q;-                  changed = 1;-               }-               step = &(*step)->next;-            }-            if (!changed) break;-         }--         // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline-         while (e->y0 <= scan_y) {-            if (e->y1 > scan_y) {-               stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);-               if (z != NULL) {-                  // find insertion point-                  if (active == NULL)-                     active = z;-                  else if (z->x < active->x) {-                     // insert at front-                     z->next = active;-                     active = z;-                  } else {-                     // find thing to insert AFTER-                     stbtt__active_edge *p = active;-                     while (p->next && p->next->x < z->x)-                        p = p->next;-                     // at this point, p->next->x is NOT < z->x-                     z->next = p->next;-                     p->next = z;-                  }-               }-            }-            ++e;-         }--         // now process all active edges in XOR fashion-         if (active)-            stbtt__fill_active_edges(scanline, result->w, active, max_weight);--         ++y;-      }-      STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);-      ++j;-   }--   stbtt__hheap_cleanup(&hh, userdata);--   if (scanline != scanline_data)-      STBTT_free(scanline, userdata);-}--#elif STBTT_RASTERIZER_VERSION == 2--// the edge passed in here does not cross the vertical line at x or the vertical line at x+1-// (i.e. it has already been clipped to those)-static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)-{-   if (y0 == y1) return;-   STBTT_assert(y0 < y1);-   STBTT_assert(e->sy <= e->ey);-   if (y0 > e->ey) return;-   if (y1 < e->sy) return;-   if (y0 < e->sy) {-      x0 += (x1-x0) * (e->sy - y0) / (y1-y0);-      y0 = e->sy;-   }-   if (y1 > e->ey) {-      x1 += (x1-x0) * (e->ey - y1) / (y1-y0);-      y1 = e->ey;-   }--   if (x0 == x)-      STBTT_assert(x1 <= x+1);-   else if (x0 == x+1)-      STBTT_assert(x1 >= x);-   else if (x0 <= x)-      STBTT_assert(x1 <= x);-   else if (x0 >= x+1)-      STBTT_assert(x1 >= x+1);-   else-      STBTT_assert(x1 >= x && x1 <= x+1);--   if (x0 <= x && x1 <= x)-      scanline[x] += e->direction * (y1-y0);-   else if (x0 >= x+1 && x1 >= x+1)-      ;-   else {-      STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);-      scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position-   }-}--static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)-{-   float y_bottom = y_top+1;--   while (e) {-      // brute force every pixel--      // compute intersection points with top & bottom-      STBTT_assert(e->ey >= y_top);--      if (e->fdx == 0) {-         float x0 = e->fx;-         if (x0 < len) {-            if (x0 >= 0) {-               stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);-               stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);-            } else {-               stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);-            }-         }-      } else {-         float x0 = e->fx;-         float dx = e->fdx;-         float xb = x0 + dx;-         float x_top, x_bottom;-         float sy0,sy1;-         float dy = e->fdy;-         STBTT_assert(e->sy <= y_bottom && e->ey >= y_top);--         // compute endpoints of line segment clipped to this scanline (if the-         // line segment starts on this scanline. x0 is the intersection of the-         // line with y_top, but that may be off the line segment.-         if (e->sy > y_top) {-            x_top = x0 + dx * (e->sy - y_top);-            sy0 = e->sy;-         } else {-            x_top = x0;-            sy0 = y_top;-         }-         if (e->ey < y_bottom) {-            x_bottom = x0 + dx * (e->ey - y_top);-            sy1 = e->ey;-         } else {-            x_bottom = xb;-            sy1 = y_bottom;-         }--         if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {-            // from here on, we don't have to range check x values--            if ((int) x_top == (int) x_bottom) {-               float height;-               // simple case, only spans one pixel-               int x = (int) x_top;-               height = sy1 - sy0;-               STBTT_assert(x >= 0 && x < len);-               scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2)  * height;-               scanline_fill[x] += e->direction * height; // everything right of this pixel is filled-            } else {-               int x,x1,x2;-               float y_crossing, step, sign, area;-               // covers 2+ pixels-               if (x_top > x_bottom) {-                  // flip scanline vertically; signed area is the same-                  float t;-                  sy0 = y_bottom - (sy0 - y_top);-                  sy1 = y_bottom - (sy1 - y_top);-                  t = sy0, sy0 = sy1, sy1 = t;-                  t = x_bottom, x_bottom = x_top, x_top = t;-                  dx = -dx;-                  dy = -dy;-                  t = x0, x0 = xb, xb = t;-               }--               x1 = (int) x_top;-               x2 = (int) x_bottom;-               // compute intersection with y axis at x1+1-               y_crossing = (x1+1 - x0) * dy + y_top;--               sign = e->direction;-               // area of the rectangle covered from y0..y_crossing-               area = sign * (y_crossing-sy0);-               // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)-               scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);--               step = sign * dy;-               for (x = x1+1; x < x2; ++x) {-                  scanline[x] += area + step/2;-                  area += step;-               }-               y_crossing += dy * (x2 - (x1+1));--               STBTT_assert(fabs(area) <= 1.01f);--               scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);--               scanline_fill[x2] += sign * (sy1-sy0);-            }-         } else {-            // if edge goes outside of box we're drawing, we require-            // clipping logic. since this does not match the intended use-            // of this library, we use a different, very slow brute-            // force implementation-            int x;-            for (x=0; x < len; ++x) {-               // cases:-               //-               // there can be up to two intersections with the pixel. any intersection-               // with left or right edges can be handled by splitting into two (or three)-               // regions. intersections with top & bottom do not necessitate case-wise logic.-               //-               // the old way of doing this found the intersections with the left & right edges,-               // then used some simple logic to produce up to three segments in sorted order-               // from top-to-bottom. however, this had a problem: if an x edge was epsilon-               // across the x border, then the corresponding y position might not be distinct-               // from the other y segment, and it might ignored as an empty segment. to avoid-               // that, we need to explicitly produce segments based on x positions.--               // rename variables to clear pairs-               float y0 = y_top;-               float x1 = (float) (x);-               float x2 = (float) (x+1);-               float x3 = xb;-               float y3 = y_bottom;-               float y1,y2;--               // x = e->x + e->dx * (y-y_top)-               // (y-y_top) = (x - e->x) / e->dx-               // y = (x - e->x) / e->dx + y_top-               y1 = (x - x0) / dx + y_top;-               y2 = (x+1 - x0) / dx + y_top;--               if (x0 < x1 && x3 > x2) {         // three segments descending down-right-                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);-                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);-                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);-               } else if (x3 < x1 && x0 > x2) {  // three segments descending down-left-                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);-                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);-                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);-               } else if (x0 < x1 && x3 > x1) {  // two segments across x, down-right-                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);-                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);-               } else if (x3 < x1 && x0 > x1) {  // two segments across x, down-left-                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);-                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);-               } else if (x0 < x2 && x3 > x2) {  // two segments across x+1, down-right-                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);-                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);-               } else if (x3 < x2 && x0 > x2) {  // two segments across x+1, down-left-                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);-                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);-               } else {  // one segment-                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);-               }-            }-         }-      }-      e = e->next;-   }-}--// directly AA rasterize edges w/o supersampling-static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)-{-   stbtt__hheap hh = { 0, 0, 0 };-   stbtt__active_edge *active = NULL;-   int y,j=0, i;-   float scanline_data[129], *scanline, *scanline2;--   if (result->w > 64)-      scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);-   else-      scanline = scanline_data;--   scanline2 = scanline + result->w;--   y = off_y;-   e[n].y0 = (float) (off_y + result->h) + 1;--   while (j < result->h) {-      // find center of pixel for this scanline-      float scan_y_top    = y + 0.0f;-      float scan_y_bottom = y + 1.0f;-      stbtt__active_edge **step = &active;--      STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));-      STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));--      // update all active edges;-      // remove all active edges that terminate before the top of this scanline-      while (*step) {-         stbtt__active_edge * z = *step;-         if (z->ey <= scan_y_top) {-            *step = z->next; // delete from list-            STBTT_assert(z->direction);-            z->direction = 0;-            stbtt__hheap_free(&hh, z);-         } else {-            step = &((*step)->next); // advance through list-         }-      }--      // insert all edges that start before the bottom of this scanline-      while (e->y0 <= scan_y_bottom) {-         if (e->y0 != e->y1) {-            stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);-            if (z != NULL) {-               STBTT_assert(z->ey >= scan_y_top);-               // insert at front-               z->next = active;-               active = z;-            }-         }-         ++e;-      }--      // now process all active edges-      if (active)-         stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);--      {-         float sum = 0;-         for (i=0; i < result->w; ++i) {-            float k;-            int m;-            sum += scanline2[i];-            k = scanline[i] + sum;-            k = (float) fabs(k)*255 + 0.5f;-            m = (int) k;-            if (m > 255) m = 255;-            result->pixels[j*result->stride + i] = (unsigned char) m;-         }-      }-      // advance all the edges-      step = &active;-      while (*step) {-         stbtt__active_edge *z = *step;-         z->fx += z->fdx; // advance to position for current scanline-         step = &((*step)->next); // advance through list-      }--      ++y;-      ++j;-   }--   stbtt__hheap_cleanup(&hh, userdata);--   if (scanline != scanline_data)-      STBTT_free(scanline, userdata);-}-#else-#error "Unrecognized value of STBTT_RASTERIZER_VERSION"-#endif--#define STBTT__COMPARE(a,b)  ((a)->y0 < (b)->y0)--static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)-{-   int i,j;-   for (i=1; i < n; ++i) {-      stbtt__edge t = p[i], *a = &t;-      j = i;-      while (j > 0) {-         stbtt__edge *b = &p[j-1];-         int c = STBTT__COMPARE(a,b);-         if (!c) break;-         p[j] = p[j-1];-         --j;-      }-      if (i != j)-         p[j] = t;-   }-}--static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)-{-   /* threshhold for transitioning to insertion sort */-   while (n > 12) {-      stbtt__edge t;-      int c01,c12,c,m,i,j;--      /* compute median of three */-      m = n >> 1;-      c01 = STBTT__COMPARE(&p[0],&p[m]);-      c12 = STBTT__COMPARE(&p[m],&p[n-1]);-      /* if 0 >= mid >= end, or 0 < mid < end, then use mid */-      if (c01 != c12) {-         /* otherwise, we'll need to swap something else to middle */-         int z;-         c = STBTT__COMPARE(&p[0],&p[n-1]);-         /* 0>mid && mid<n:  0>n => n; 0<n => 0 */-         /* 0<mid && mid>n:  0>n => 0; 0<n => n */-         z = (c == c12) ? 0 : n-1;-         t = p[z];-         p[z] = p[m];-         p[m] = t;-      }-      /* now p[m] is the median-of-three */-      /* swap it to the beginning so it won't move around */-      t = p[0];-      p[0] = p[m];-      p[m] = t;--      /* partition loop */-      i=1;-      j=n-1;-      for(;;) {-         /* handling of equality is crucial here */-         /* for sentinels & efficiency with duplicates */-         for (;;++i) {-            if (!STBTT__COMPARE(&p[i], &p[0])) break;-         }-         for (;;--j) {-            if (!STBTT__COMPARE(&p[0], &p[j])) break;-         }-         /* make sure we haven't crossed */-         if (i >= j) break;-         t = p[i];-         p[i] = p[j];-         p[j] = t;--         ++i;-         --j;-      }-      /* recurse on smaller side, iterate on larger */-      if (j < (n-i)) {-         stbtt__sort_edges_quicksort(p,j);-         p = p+i;-         n = n-i;-      } else {-         stbtt__sort_edges_quicksort(p+i, n-i);-         n = j;-      }-   }-}--static void stbtt__sort_edges(stbtt__edge *p, int n)-{-   stbtt__sort_edges_quicksort(p, n);-   stbtt__sort_edges_ins_sort(p, n);-}--typedef struct-{-   float x,y;-} stbtt__point;--static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)-{-   float y_scale_inv = invert ? -scale_y : scale_y;-   stbtt__edge *e;-   int n,i,j,k,m;-#if STBTT_RASTERIZER_VERSION == 1-   int vsubsample = result->h < 8 ? 15 : 5;-#elif STBTT_RASTERIZER_VERSION == 2-   int vsubsample = 1;-#else-   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"-#endif-   // vsubsample should divide 255 evenly; otherwise we won't reach full opacity--   // now we have to blow out the windings into explicit edge lists-   n = 0;-   for (i=0; i < windings; ++i)-      n += wcount[i];--   e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel-   if (e == 0) return;-   n = 0;--   m=0;-   for (i=0; i < windings; ++i) {-      stbtt__point *p = pts + m;-      m += wcount[i];-      j = wcount[i]-1;-      for (k=0; k < wcount[i]; j=k++) {-         int a=k,b=j;-         // skip the edge if horizontal-         if (p[j].y == p[k].y)-            continue;-         // add edge from j to k to the list-         e[n].invert = 0;-         if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {-            e[n].invert = 1;-            a=j,b=k;-         }-         e[n].x0 = p[a].x * scale_x + shift_x;-         e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;-         e[n].x1 = p[b].x * scale_x + shift_x;-         e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;-         ++n;-      }-   }--   // now sort the edges by their highest point (should snap to integer, and then by x)-   //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);-   stbtt__sort_edges(e, n);--   // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule-   stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);--   STBTT_free(e, userdata);-}--static void stbtt__add_point(stbtt__point *points, int n, float x, float y)-{-   if (!points) return; // during first pass, it's unallocated-   points[n].x = x;-   points[n].y = y;-}--// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching-static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)-{-   // midpoint-   float mx = (x0 + 2*x1 + x2)/4;-   float my = (y0 + 2*y1 + y2)/4;-   // versus directly drawn line-   float dx = (x0+x2)/2 - mx;-   float dy = (y0+y2)/2 - my;-   if (n > 16) // 65536 segments on one curve better be enough!-      return 1;-   if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA-      stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);-      stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);-   } else {-      stbtt__add_point(points, *num_points,x2,y2);-      *num_points = *num_points+1;-   }-   return 1;-}--// returns number of contours-static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)-{-   stbtt__point *points=0;-   int num_points=0;--   float objspace_flatness_squared = objspace_flatness * objspace_flatness;-   int i,n=0,start=0, pass;--   // count how many "moves" there are to get the contour count-   for (i=0; i < num_verts; ++i)-      if (vertices[i].type == STBTT_vmove)-         ++n;--   *num_contours = n;-   if (n == 0) return 0;--   *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);--   if (*contour_lengths == 0) {-      *num_contours = 0;-      return 0;-   }--   // make two passes through the points so we don't need to realloc-   for (pass=0; pass < 2; ++pass) {-      float x=0,y=0;-      if (pass == 1) {-         points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);-         if (points == NULL) goto error;-      }-      num_points = 0;-      n= -1;-      for (i=0; i < num_verts; ++i) {-         switch (vertices[i].type) {-            case STBTT_vmove:-               // start the next contour-               if (n >= 0)-                  (*contour_lengths)[n] = num_points - start;-               ++n;-               start = num_points;--               x = vertices[i].x, y = vertices[i].y;-               stbtt__add_point(points, num_points++, x,y);-               break;-            case STBTT_vline:-               x = vertices[i].x, y = vertices[i].y;-               stbtt__add_point(points, num_points++, x, y);-               break;-            case STBTT_vcurve:-               stbtt__tesselate_curve(points, &num_points, x,y,-                                        vertices[i].cx, vertices[i].cy,-                                        vertices[i].x,  vertices[i].y,-                                        objspace_flatness_squared, 0);-               x = vertices[i].x, y = vertices[i].y;-               break;-         }-      }-      (*contour_lengths)[n] = num_points - start;-   }--   return points;-error:-   STBTT_free(points, userdata);-   STBTT_free(*contour_lengths, userdata);-   *contour_lengths = 0;-   *num_contours = 0;-   return NULL;-}--STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)-{-   float scale = scale_x > scale_y ? scale_y : scale_x;-   int winding_count, *winding_lengths;-   stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);-   if (windings) {-      stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);-      STBTT_free(winding_lengths, userdata);-      STBTT_free(windings, userdata);-   }-}--STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)-{-   STBTT_free(bitmap, userdata);-}--STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)-{-   int ix0,iy0,ix1,iy1;-   stbtt__bitmap gbm;-   stbtt_vertex *vertices;   -   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);--   if (scale_x == 0) scale_x = scale_y;-   if (scale_y == 0) {-      if (scale_x == 0) return NULL;-      scale_y = scale_x;-   }--   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);--   // now we get the size-   gbm.w = (ix1 - ix0);-   gbm.h = (iy1 - iy0);-   gbm.pixels = NULL; // in case we error--   if (width ) *width  = gbm.w;-   if (height) *height = gbm.h;-   if (xoff  ) *xoff   = ix0;-   if (yoff  ) *yoff   = iy0;-   -   if (gbm.w && gbm.h) {-      gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);-      if (gbm.pixels) {-         gbm.stride = gbm.w;--         stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);-      }-   }-   STBTT_free(vertices, info->userdata);-   return gbm.pixels;-}   --STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)-{-   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);-}--STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)-{-   int ix0,iy0;-   stbtt_vertex *vertices;-   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);-   stbtt__bitmap gbm;   --   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);-   gbm.pixels = output;-   gbm.w = out_w;-   gbm.h = out_h;-   gbm.stride = out_stride;--   if (gbm.w && gbm.h)-      stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);--   STBTT_free(vertices, info->userdata);-}--STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)-{-   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);-}--STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)-{-   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);-}   --STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)-{-   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));-}--STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)-{-   return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);-}   --STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)-{-   stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);-}--//////////////////////////////////////////////////////////////////////////////-//-// bitmap baking-//-// This is SUPER-CRAPPY packing to keep source code small--STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)-                                float pixel_height,                     // height of font in pixels-                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in-                                int first_char, int num_chars,          // characters to bake-                                stbtt_bakedchar *chardata)-{-   float scale;-   int x,y,bottom_y, i;-   stbtt_fontinfo f;-   f.userdata = NULL;-   if (!stbtt_InitFont(&f, data, offset))-      return -1;-   STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels-   x=y=1;-   bottom_y = 1;--   scale = stbtt_ScaleForPixelHeight(&f, pixel_height);--   for (i=0; i < num_chars; ++i) {-      int advance, lsb, x0,y0,x1,y1,gw,gh;-      int g = stbtt_FindGlyphIndex(&f, first_char + i);-      stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);-      stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);-      gw = x1-x0;-      gh = y1-y0;-      if (x + gw + 1 >= pw)-         y = bottom_y, x = 1; // advance to next row-      if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row-         return -i;-      STBTT_assert(x+gw < pw);-      STBTT_assert(y+gh < ph);-      stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);-      chardata[i].x0 = (stbtt_int16) x;-      chardata[i].y0 = (stbtt_int16) y;-      chardata[i].x1 = (stbtt_int16) (x + gw);-      chardata[i].y1 = (stbtt_int16) (y + gh);-      chardata[i].xadvance = scale * advance;-      chardata[i].xoff     = (float) x0;-      chardata[i].yoff     = (float) y0;-      x = x + gw + 1;-      if (y+gh+1 > bottom_y)-         bottom_y = y+gh+1;-   }-   return bottom_y;-}--STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)-{-   float d3d_bias = opengl_fillrule ? 0 : -0.5f;-   float ipw = 1.0f / pw, iph = 1.0f / ph;-   stbtt_bakedchar *b = chardata + char_index;-   int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);-   int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);--   q->x0 = round_x + d3d_bias;-   q->y0 = round_y + d3d_bias;-   q->x1 = round_x + b->x1 - b->x0 + d3d_bias;-   q->y1 = round_y + b->y1 - b->y0 + d3d_bias;--   q->s0 = b->x0 * ipw;-   q->t0 = b->y0 * iph;-   q->s1 = b->x1 * ipw;-   q->t1 = b->y1 * iph;--   *xpos += b->xadvance;-}--//////////////////////////////////////////////////////////////////////////////-//-// rectangle packing replacement routines if you don't have stb_rect_pack.h-//--#ifndef STB_RECT_PACK_VERSION-#ifdef _MSC_VER-#define STBTT__NOTUSED(v)  (void)(v)-#else-#define STBTT__NOTUSED(v)  (void)sizeof(v)-#endif--typedef int stbrp_coord;--////////////////////////////////////////////////////////////////////////////////////-//                                                                                //-//                                                                                //-// COMPILER WARNING ?!?!?                                                         //-//                                                                                //-//                                                                                //-// if you get a compile warning due to these symbols being defined more than      //-// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h"         //-//                                                                                //-////////////////////////////////////////////////////////////////////////////////////--typedef struct-{-   int width,height;-   int x,y,bottom_y;-} stbrp_context;--typedef struct-{-   unsigned char x;-} stbrp_node;--struct stbrp_rect-{-   stbrp_coord x,y;-   int id,w,h,was_packed;-};--static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)-{-   con->width  = pw;-   con->height = ph;-   con->x = 0;-   con->y = 0;-   con->bottom_y = 0;-   STBTT__NOTUSED(nodes);-   STBTT__NOTUSED(num_nodes);   -}--static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)-{-   int i;-   for (i=0; i < num_rects; ++i) {-      if (con->x + rects[i].w > con->width) {-         con->x = 0;-         con->y = con->bottom_y;-      }-      if (con->y + rects[i].h > con->height)-         break;-      rects[i].x = con->x;-      rects[i].y = con->y;-      rects[i].was_packed = 1;-      con->x += rects[i].w;-      if (con->y + rects[i].h > con->bottom_y)-         con->bottom_y = con->y + rects[i].h;-   }-   for (   ; i < num_rects; ++i)-      rects[i].was_packed = 0;-}-#endif--//////////////////////////////////////////////////////////////////////////////-//-// bitmap baking-//-// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If-// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy.--STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)-{-   stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context)            ,alloc_context);-   int            num_nodes = pw - padding;-   stbrp_node    *nodes   = (stbrp_node    *) STBTT_malloc(sizeof(*nodes  ) * num_nodes,alloc_context);--   if (context == NULL || nodes == NULL) {-      if (context != NULL) STBTT_free(context, alloc_context);-      if (nodes   != NULL) STBTT_free(nodes  , alloc_context);-      return 0;-   }--   spc->user_allocator_context = alloc_context;-   spc->width = pw;-   spc->height = ph;-   spc->pixels = pixels;-   spc->pack_info = context;-   spc->nodes = nodes;-   spc->padding = padding;-   spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;-   spc->h_oversample = 1;-   spc->v_oversample = 1;--   stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);--   if (pixels)-      STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels--   return 1;-}--STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc)-{-   STBTT_free(spc->nodes    , spc->user_allocator_context);-   STBTT_free(spc->pack_info, spc->user_allocator_context);-}--STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample)-{-   STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE);-   STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE);-   if (h_oversample <= STBTT_MAX_OVERSAMPLE)-      spc->h_oversample = h_oversample;-   if (v_oversample <= STBTT_MAX_OVERSAMPLE)-      spc->v_oversample = v_oversample;-}--#define STBTT__OVER_MASK  (STBTT_MAX_OVERSAMPLE-1)--static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)-{-   unsigned char buffer[STBTT_MAX_OVERSAMPLE];-   int safe_w = w - kernel_width;-   int j;-   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze-   for (j=0; j < h; ++j) {-      int i;-      unsigned int total;-      STBTT_memset(buffer, 0, kernel_width);--      total = 0;--      // make kernel_width a constant in common cases so compiler can optimize out the divide-      switch (kernel_width) {-         case 2:-            for (i=0; i <= safe_w; ++i) {-               total += pixels[i] - buffer[i & STBTT__OVER_MASK];-               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];-               pixels[i] = (unsigned char) (total / 2);-            }-            break;-         case 3:-            for (i=0; i <= safe_w; ++i) {-               total += pixels[i] - buffer[i & STBTT__OVER_MASK];-               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];-               pixels[i] = (unsigned char) (total / 3);-            }-            break;-         case 4:-            for (i=0; i <= safe_w; ++i) {-               total += pixels[i] - buffer[i & STBTT__OVER_MASK];-               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];-               pixels[i] = (unsigned char) (total / 4);-            }-            break;-         case 5:-            for (i=0; i <= safe_w; ++i) {-               total += pixels[i] - buffer[i & STBTT__OVER_MASK];-               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];-               pixels[i] = (unsigned char) (total / 5);-            }-            break;-         default:-            for (i=0; i <= safe_w; ++i) {-               total += pixels[i] - buffer[i & STBTT__OVER_MASK];-               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];-               pixels[i] = (unsigned char) (total / kernel_width);-            }-            break;-      }--      for (; i < w; ++i) {-         STBTT_assert(pixels[i] == 0);-         total -= buffer[i & STBTT__OVER_MASK];-         pixels[i] = (unsigned char) (total / kernel_width);-      }--      pixels += stride_in_bytes;-   }-}--static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)-{-   unsigned char buffer[STBTT_MAX_OVERSAMPLE];-   int safe_h = h - kernel_width;-   int j;-   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze-   for (j=0; j < w; ++j) {-      int i;-      unsigned int total;-      STBTT_memset(buffer, 0, kernel_width);--      total = 0;--      // make kernel_width a constant in common cases so compiler can optimize out the divide-      switch (kernel_width) {-         case 2:-            for (i=0; i <= safe_h; ++i) {-               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];-               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];-               pixels[i*stride_in_bytes] = (unsigned char) (total / 2);-            }-            break;-         case 3:-            for (i=0; i <= safe_h; ++i) {-               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];-               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];-               pixels[i*stride_in_bytes] = (unsigned char) (total / 3);-            }-            break;-         case 4:-            for (i=0; i <= safe_h; ++i) {-               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];-               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];-               pixels[i*stride_in_bytes] = (unsigned char) (total / 4);-            }-            break;-         case 5:-            for (i=0; i <= safe_h; ++i) {-               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];-               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];-               pixels[i*stride_in_bytes] = (unsigned char) (total / 5);-            }-            break;-         default:-            for (i=0; i <= safe_h; ++i) {-               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];-               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];-               pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);-            }-            break;-      }--      for (; i < h; ++i) {-         STBTT_assert(pixels[i*stride_in_bytes] == 0);-         total -= buffer[i & STBTT__OVER_MASK];-         pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);-      }--      pixels += 1;-   }-}--static float stbtt__oversample_shift(int oversample)-{-   if (!oversample)-      return 0.0f;--   // The prefilter is a box filter of width "oversample",-   // which shifts phase by (oversample - 1)/2 pixels in-   // oversampled space. We want to shift in the opposite-   // direction to counter this.-   return (float)-(oversample - 1) / (2.0f * (float)oversample);-}--// rects array must be big enough to accommodate all characters in the given ranges-STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)-{-   int i,j,k;--   k=0;-   for (i=0; i < num_ranges; ++i) {-      float fh = ranges[i].font_size;-      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);-      ranges[i].h_oversample = (unsigned char) spc->h_oversample;-      ranges[i].v_oversample = (unsigned char) spc->v_oversample;-      for (j=0; j < ranges[i].num_chars; ++j) {-         int x0,y0,x1,y1;-         int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];-         int glyph = stbtt_FindGlyphIndex(info, codepoint);-         stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,-                                         scale * spc->h_oversample,-                                         scale * spc->v_oversample,-                                         0,0,-                                         &x0,&y0,&x1,&y1);-         rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);-         rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);-         ++k;-      }-   }--   return k;-}--// rects array must be big enough to accommodate all characters in the given ranges-STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)-{-   int i,j,k, return_value = 1;--   // save current values-   int old_h_over = spc->h_oversample;-   int old_v_over = spc->v_oversample;--   k = 0;-   for (i=0; i < num_ranges; ++i) {-      float fh = ranges[i].font_size;-      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);-      float recip_h,recip_v,sub_x,sub_y;-      spc->h_oversample = ranges[i].h_oversample;-      spc->v_oversample = ranges[i].v_oversample;-      recip_h = 1.0f / spc->h_oversample;-      recip_v = 1.0f / spc->v_oversample;-      sub_x = stbtt__oversample_shift(spc->h_oversample);-      sub_y = stbtt__oversample_shift(spc->v_oversample);-      for (j=0; j < ranges[i].num_chars; ++j) {-         stbrp_rect *r = &rects[k];-         if (r->was_packed) {-            stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];-            int advance, lsb, x0,y0,x1,y1;-            int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];-            int glyph = stbtt_FindGlyphIndex(info, codepoint);-            stbrp_coord pad = (stbrp_coord) spc->padding;--            // pad on left and top-            r->x += pad;-            r->y += pad;-            r->w -= pad;-            r->h -= pad;-            stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);-            stbtt_GetGlyphBitmapBox(info, glyph,-                                    scale * spc->h_oversample,-                                    scale * spc->v_oversample,-                                    &x0,&y0,&x1,&y1);-            stbtt_MakeGlyphBitmapSubpixel(info,-                                          spc->pixels + r->x + r->y*spc->stride_in_bytes,-                                          r->w - spc->h_oversample+1,-                                          r->h - spc->v_oversample+1,-                                          spc->stride_in_bytes,-                                          scale * spc->h_oversample,-                                          scale * spc->v_oversample,-                                          0,0,-                                          glyph);--            if (spc->h_oversample > 1)-               stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,-                                  r->w, r->h, spc->stride_in_bytes,-                                  spc->h_oversample);--            if (spc->v_oversample > 1)-               stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,-                                  r->w, r->h, spc->stride_in_bytes,-                                  spc->v_oversample);--            bc->x0       = (stbtt_int16)  r->x;-            bc->y0       = (stbtt_int16)  r->y;-            bc->x1       = (stbtt_int16) (r->x + r->w);-            bc->y1       = (stbtt_int16) (r->y + r->h);-            bc->xadvance =                scale * advance;-            bc->xoff     =       (float)  x0 * recip_h + sub_x;-            bc->yoff     =       (float)  y0 * recip_v + sub_y;-            bc->xoff2    =                (x0 + r->w) * recip_h + sub_x;-            bc->yoff2    =                (y0 + r->h) * recip_v + sub_y;-         } else {-            return_value = 0; // if any fail, report failure-         }--         ++k;-      }-   }--   // restore original values-   spc->h_oversample = old_h_over;-   spc->v_oversample = old_v_over;--   return return_value;-}--STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)-{-   stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);-}--STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)-{-   stbtt_fontinfo info;-   int i,j,n, return_value = 1;-   //stbrp_context *context = (stbrp_context *) spc->pack_info;-   stbrp_rect    *rects;--   // flag all characters as NOT packed-   for (i=0; i < num_ranges; ++i)-      for (j=0; j < ranges[i].num_chars; ++j)-         ranges[i].chardata_for_range[j].x0 =-         ranges[i].chardata_for_range[j].y0 =-         ranges[i].chardata_for_range[j].x1 =-         ranges[i].chardata_for_range[j].y1 = 0;--   n = 0;-   for (i=0; i < num_ranges; ++i)-      n += ranges[i].num_chars;-         -   rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);-   if (rects == NULL)-      return 0;--   info.userdata = spc->user_allocator_context;-   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));--   n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);--   stbtt_PackFontRangesPackRects(spc, rects, n);-  -   return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);--   STBTT_free(rects, spc->user_allocator_context);-   return return_value;-}--STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,-            int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)-{-   stbtt_pack_range range;-   range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;-   range.array_of_unicode_codepoints = NULL;-   range.num_chars                   = num_chars_in_range;-   range.chardata_for_range          = chardata_for_range;-   range.font_size                   = font_size;-   return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);-}--STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)-{-   float ipw = 1.0f / pw, iph = 1.0f / ph;-   stbtt_packedchar *b = chardata + char_index;--   if (align_to_integer) {-      float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);-      float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);-      q->x0 = x;-      q->y0 = y;-      q->x1 = x + b->xoff2 - b->xoff;-      q->y1 = y + b->yoff2 - b->yoff;-   } else {-      q->x0 = *xpos + b->xoff;-      q->y0 = *ypos + b->yoff;-      q->x1 = *xpos + b->xoff2;-      q->y1 = *ypos + b->yoff2;-   }--   q->s0 = b->x0 * ipw;-   q->t0 = b->y0 * iph;-   q->s1 = b->x1 * ipw;-   q->t1 = b->y1 * iph;--   *xpos += b->xadvance;-}---//////////////////////////////////////////////////////////////////////////////-//-// font name matching -- recommended not to use this-//--// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string-static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8 *s1, stbtt_int32 len1, const stbtt_uint8 *s2, stbtt_int32 len2) -{-   stbtt_int32 i=0;--   // convert utf16 to utf8 and compare the results while converting-   while (len2) {-      stbtt_uint16 ch = s2[0]*256 + s2[1];-      if (ch < 0x80) {-         if (i >= len1) return -1;-         if (s1[i++] != ch) return -1;-      } else if (ch < 0x800) {-         if (i+1 >= len1) return -1;-         if (s1[i++] != 0xc0 + (ch >> 6)) return -1;-         if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;-      } else if (ch >= 0xd800 && ch < 0xdc00) {-         stbtt_uint32 c;-         stbtt_uint16 ch2 = s2[2]*256 + s2[3];-         if (i+3 >= len1) return -1;-         c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;-         if (s1[i++] != 0xf0 + (c >> 18)) return -1;-         if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;-         if (s1[i++] != 0x80 + ((c >>  6) & 0x3f)) return -1;-         if (s1[i++] != 0x80 + ((c      ) & 0x3f)) return -1;-         s2 += 2; // plus another 2 below-         len2 -= 2;-      } else if (ch >= 0xdc00 && ch < 0xe000) {-         return -1;-      } else {-         if (i+2 >= len1) return -1;-         if (s1[i++] != 0xe0 + (ch >> 12)) return -1;-         if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;-         if (s1[i++] != 0x80 + ((ch     ) & 0x3f)) return -1;-      }-      s2 += 2;-      len2 -= 2;-   }-   return i;-}--STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) -{-   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((const stbtt_uint8*) s1, len1, (const stbtt_uint8*) s2, len2);-}--// returns results in whatever encoding you request... but note that 2-byte encodings-// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare-STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)-{-   stbtt_int32 i,count,stringOffset;-   stbtt_uint8 *fc = font->data;-   stbtt_uint32 offset = font->fontstart;-   stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");-   if (!nm) return NULL;--   count = ttUSHORT(fc+nm+2);-   stringOffset = nm + ttUSHORT(fc+nm+4);-   for (i=0; i < count; ++i) {-      stbtt_uint32 loc = nm + 6 + 12 * i;-      if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)-          && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {-         *length = ttUSHORT(fc+loc+8);-         return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));-      }-   }-   return NULL;-}--static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)-{-   stbtt_int32 i;-   stbtt_int32 count = ttUSHORT(fc+nm+2);-   stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);--   for (i=0; i < count; ++i) {-      stbtt_uint32 loc = nm + 6 + 12 * i;-      stbtt_int32 id = ttUSHORT(fc+loc+6);-      if (id == target_id) {-         // find the encoding-         stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);--         // is this a Unicode encoding?-         if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {-            stbtt_int32 slen = ttUSHORT(fc+loc+8);-            stbtt_int32 off = ttUSHORT(fc+loc+10);--            // check if there's a prefix match-            stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);-            if (matchlen >= 0) {-               // check for target_id+1 immediately following, with same encoding & language-               if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {-                  slen = ttUSHORT(fc+loc+12+8);-                  off = ttUSHORT(fc+loc+12+10);-                  if (slen == 0) {-                     if (matchlen == nlen)-                        return 1;-                  } else if (matchlen < nlen && name[matchlen] == ' ') {-                     ++matchlen;-                     if (stbtt_CompareUTF8toUTF16_bigendian((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))-                        return 1;-                  }-               } else {-                  // if nothing immediately following-                  if (matchlen == nlen)-                     return 1;-               }-            }-         }--         // @TODO handle other encodings-      }-   }-   return 0;-}--static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)-{-   stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);-   stbtt_uint32 nm,hd;-   if (!stbtt__isfont(fc+offset)) return 0;--   // check italics/bold/underline flags in macStyle...-   if (flags) {-      hd = stbtt__find_table(fc, offset, "head");-      if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;-   }--   nm = stbtt__find_table(fc, offset, "name");-   if (!nm) return 0;--   if (flags) {-      // if we checked the macStyle flags, then just check the family and ignore the subfamily-      if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))  return 1;-      if (stbtt__matchpair(fc, nm, name, nlen,  1, -1))  return 1;-      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;-   } else {-      if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))  return 1;-      if (stbtt__matchpair(fc, nm, name, nlen,  1,  2))  return 1;-      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;-   }--   return 0;-}--STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *font_collection, const char *name_utf8, stbtt_int32 flags)-{-   stbtt_int32 i;-   for (i=0;;++i) {-      stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);-      if (off < 0) return off;-      if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))-         return off;-   }-}--#endif // STB_TRUETYPE_IMPLEMENTATION---// FULL VERSION HISTORY-//-//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges-//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges-//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;-//                     allow PackFontRanges to pack and render in separate phases;-//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);-//                     fixed an assert() bug in the new rasterizer-//                     replace assert() with STBTT_assert() in new rasterizer-//   1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)-//                     also more precise AA rasterizer, except if shapes overlap-//                     remove need for STBTT_sort-//   1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC-//   1.04 (2015-04-15) typo in example-//   1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes-//   1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++-//   1.01 (2014-12-08) fix subpixel position when oversampling to exactly match-//                        non-oversampled; STBTT_POINT_SIZE for packed case only-//   1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling-//   0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg)-//   0.9  (2014-08-07) support certain mac/iOS fonts without an MS platformID-//   0.8b (2014-07-07) fix a warning-//   0.8  (2014-05-25) fix a few more warnings-//   0.7  (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back-//   0.6c (2012-07-24) improve documentation-//   0.6b (2012-07-20) fix a few more warnings-//   0.6  (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,-//                        stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty-//   0.5  (2011-12-09) bugfixes:-//                        subpixel glyph renderer computed wrong bounding box-//                        first vertex of shape can be off-curve (FreeSans)-//   0.4b (2011-12-03) fixed an error in the font baking example-//   0.4  (2011-12-01) kerning, subpixel rendering (tor)-//                    bugfixes for:-//                        codepoint-to-glyph conversion using table fmt=12-//                        codepoint-to-glyph conversion using table fmt=4-//                        stbtt_GetBakedQuad with non-square texture (Zer)-//                    updated Hello World! sample to use kerning and subpixel-//                    fixed some warnings-//   0.3  (2009-06-24) cmap fmt=12, compound shapes (MM)-//                    userdata, malloc-from-userdata, non-zero fill (stb)-//   0.2  (2009-03-11) Fix unsigned/signed char warnings-//   0.1  (2009-03-09) First public release-//+// stb_truetype.h - v1.24 - public domain+// authored from 2009-2020 by Sean Barrett / RAD Game Tools+//+// =======================================================================+//+//    NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES+//+// This library does no range checking of the offsets found in the file,+// meaning an attacker can use it to read arbitrary memory.+//+// =======================================================================+//+//   This library processes TrueType files:+//        parse files+//        extract glyph metrics+//        extract glyph shapes+//        render glyphs to one-channel bitmaps with antialiasing (box filter)+//        render glyphs to one-channel SDF bitmaps (signed-distance field/function)+//+//   Todo:+//        non-MS cmaps+//        crashproof on bad data+//        hinting? (no longer patented)+//        cleartype-style AA?+//        optimize: use simple memory allocator for intermediates+//        optimize: build edge-list directly from curves+//        optimize: rasterize directly from curves?+//+// ADDITIONAL CONTRIBUTORS+//+//   Mikko Mononen: compound shape support, more cmap formats+//   Tor Andersson: kerning, subpixel rendering+//   Dougall Johnson: OpenType / Type 2 font handling+//   Daniel Ribeiro Maciel: basic GPOS-based kerning+//+//   Misc other:+//       Ryan Gordon+//       Simon Glass+//       github:IntellectualKitty+//       Imanol Celaya+//       Daniel Ribeiro Maciel+//+//   Bug/warning reports/fixes:+//       "Zer" on mollyrocket       Fabian "ryg" Giesen   github:NiLuJe+//       Cass Everitt               Martins Mozeiko       github:aloucks+//       stoiko (Haemimont Games)   Cap Petschulat        github:oyvindjam+//       Brian Hook                 Omar Cornut           github:vassvik+//       Walter van Niftrik         Ryan Griege+//       David Gow                  Peter LaValle+//       David Given                Sergey Popov+//       Ivan-Assen Ivanov          Giumo X. Clanjor+//       Anthony Pesch              Higor Euripedes+//       Johan Duparc               Thomas Fields+//       Hou Qiming                 Derek Vinyard+//       Rob Loach                  Cort Stratton+//       Kenney Phillis Jr.         Brian Costabile+//       Ken Voskuil (kaesve)+//+// VERSION HISTORY+//+//   1.24 (2020-02-05) fix warning+//   1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)+//   1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined+//   1.21 (2019-02-25) fix warning+//   1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()+//   1.19 (2018-02-11) GPOS kerning, STBTT_fmod+//   1.18 (2018-01-29) add missing function+//   1.17 (2017-07-23) make more arguments const; doc fix+//   1.16 (2017-07-12) SDF support+//   1.15 (2017-03-03) make more arguments const+//   1.14 (2017-01-16) num-fonts-in-TTC function+//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts+//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual+//   1.11 (2016-04-02) fix unused-variable warning+//   1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef+//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly+//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges+//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;+//                     variant PackFontRanges to pack and render in separate phases;+//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);+//                     fixed an assert() bug in the new rasterizer+//                     replace assert() with STBTT_assert() in new rasterizer+//+//   Full history can be found at the end of this file.+//+// LICENSE+//+//   See end of file for license information.+//+// USAGE+//+//   Include this file in whatever places need to refer to it. In ONE C/C+++//   file, write:+//      #define STB_TRUETYPE_IMPLEMENTATION+//   before the #include of this file. This expands out the actual+//   implementation into that C/C++ file.+//+//   To make the implementation private to the file that generates the implementation,+//      #define STBTT_STATIC+//+//   Simple 3D API (don't ship this, but it's fine for tools and quick start)+//           stbtt_BakeFontBitmap()               -- bake a font to a bitmap for use as texture+//           stbtt_GetBakedQuad()                 -- compute quad to draw for a given char+//+//   Improved 3D API (more shippable):+//           #include "stb_rect_pack.h"           -- optional, but you really want it+//           stbtt_PackBegin()+//           stbtt_PackSetOversampling()          -- for improved quality on small fonts+//           stbtt_PackFontRanges()               -- pack and renders+//           stbtt_PackEnd()+//           stbtt_GetPackedQuad()+//+//   "Load" a font file from a memory buffer (you have to keep the buffer loaded)+//           stbtt_InitFont()+//           stbtt_GetFontOffsetForIndex()        -- indexing for TTC font collections+//           stbtt_GetNumberOfFonts()             -- number of fonts for TTC font collections+//+//   Render a unicode codepoint to a bitmap+//           stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap+//           stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide+//           stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be+//+//   Character advance/positioning+//           stbtt_GetCodepointHMetrics()+//           stbtt_GetFontVMetrics()+//           stbtt_GetFontVMetricsOS2()+//           stbtt_GetCodepointKernAdvance()+//+//   Starting with version 1.06, the rasterizer was replaced with a new,+//   faster and generally-more-precise rasterizer. The new rasterizer more+//   accurately measures pixel coverage for anti-aliasing, except in the case+//   where multiple shapes overlap, in which case it overestimates the AA pixel+//   coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If+//   this turns out to be a problem, you can re-enable the old rasterizer with+//        #define STBTT_RASTERIZER_VERSION 1+//   which will incur about a 15% speed hit.+//+// ADDITIONAL DOCUMENTATION+//+//   Immediately after this block comment are a series of sample programs.+//+//   After the sample programs is the "header file" section. This section+//   includes documentation for each API function.+//+//   Some important concepts to understand to use this library:+//+//      Codepoint+//         Characters are defined by unicode codepoints, e.g. 65 is+//         uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is+//         the hiragana for "ma".+//+//      Glyph+//         A visual character shape (every codepoint is rendered as+//         some glyph)+//+//      Glyph index+//         A font-specific integer ID representing a glyph+//+//      Baseline+//         Glyph shapes are defined relative to a baseline, which is the+//         bottom of uppercase characters. Characters extend both above+//         and below the baseline.+//+//      Current Point+//         As you draw text to the screen, you keep track of a "current point"+//         which is the origin of each character. The current point's vertical+//         position is the baseline. Even "baked fonts" use this model.+//+//      Vertical Font Metrics+//         The vertical qualities of the font, used to vertically position+//         and space the characters. See docs for stbtt_GetFontVMetrics.+//+//      Font Size in Pixels or Points+//         The preferred interface for specifying font sizes in stb_truetype+//         is to specify how tall the font's vertical extent should be in pixels.+//         If that sounds good enough, skip the next paragraph.+//+//         Most font APIs instead use "points", which are a common typographic+//         measurement for describing font size, defined as 72 points per inch.+//         stb_truetype provides a point API for compatibility. However, true+//         "per inch" conventions don't make much sense on computer displays+//         since different monitors have different number of pixels per+//         inch. For example, Windows traditionally uses a convention that+//         there are 96 pixels per inch, thus making 'inch' measurements have+//         nothing to do with inches, and thus effectively defining a point to+//         be 1.333 pixels. Additionally, the TrueType font data provides+//         an explicit scale factor to scale a given font's glyphs to points,+//         but the author has observed that this scale factor is often wrong+//         for non-commercial fonts, thus making fonts scaled in points+//         according to the TrueType spec incoherently sized in practice.+//+// DETAILED USAGE:+//+//  Scale:+//    Select how high you want the font to be, in points or pixels.+//    Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute+//    a scale factor SF that will be used by all other functions.+//+//  Baseline:+//    You need to select a y-coordinate that is the baseline of where+//    your text will appear. Call GetFontBoundingBox to get the baseline-relative+//    bounding box for all characters. SF*-y0 will be the distance in pixels+//    that the worst-case character could extend above the baseline, so if+//    you want the top edge of characters to appear at the top of the+//    screen where y=0, then you would set the baseline to SF*-y0.+//+//  Current point:+//    Set the current point where the first character will appear. The+//    first character could extend left of the current point; this is font+//    dependent. You can either choose a current point that is the leftmost+//    point and hope, or add some padding, or check the bounding box or+//    left-side-bearing of the first character to be displayed and set+//    the current point based on that.+//+//  Displaying a character:+//    Compute the bounding box of the character. It will contain signed values+//    relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,+//    then the character should be displayed in the rectangle from+//    <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).+//+//  Advancing for the next character:+//    Call GlyphHMetrics, and compute 'current_point += SF * advance'.+//+//+// ADVANCED USAGE+//+//   Quality:+//+//    - Use the functions with Subpixel at the end to allow your characters+//      to have subpixel positioning. Since the font is anti-aliased, not+//      hinted, this is very import for quality. (This is not possible with+//      baked fonts.)+//+//    - Kerning is now supported, and if you're supporting subpixel rendering+//      then kerning is worth using to give your text a polished look.+//+//   Performance:+//+//    - Convert Unicode codepoints to glyph indexes and operate on the glyphs;+//      if you don't do this, stb_truetype is forced to do the conversion on+//      every call.+//+//    - There are a lot of memory allocations. We should modify it to take+//      a temp buffer and allocate from the temp buffer (without freeing),+//      should help performance a lot.+//+// NOTES+//+//   The system uses the raw data found in the .ttf file without changing it+//   and without building auxiliary data structures. This is a bit inefficient+//   on little-endian systems (the data is big-endian), but assuming you're+//   caching the bitmaps or glyph shapes this shouldn't be a big deal.+//+//   It appears to be very hard to programmatically determine what font a+//   given file is in a general way. I provide an API for this, but I don't+//   recommend it.+//+//+// PERFORMANCE MEASUREMENTS FOR 1.06:+//+//                      32-bit     64-bit+//   Previous release:  8.83 s     7.68 s+//   Pool allocations:  7.72 s     6.34 s+//   Inline sort     :  6.54 s     5.65 s+//   New rasterizer  :  5.63 s     5.00 s++//////////////////////////////////////////////////////////////////////////////+//////////////////////////////////////////////////////////////////////////////+////+////  SAMPLE PROGRAMS+////+//+//  Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless+//+#if 0+#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation+#include "stb_truetype.h"++unsigned char ttf_buffer[1<<20];+unsigned char temp_bitmap[512*512];++stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs+GLuint ftex;++void my_stbtt_initfont(void)+{+   fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));+   stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!+   // can free ttf_buffer at this point+   glGenTextures(1, &ftex);+   glBindTexture(GL_TEXTURE_2D, ftex);+   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);+   // can free temp_bitmap at this point+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);+}++void my_stbtt_print(float x, float y, char *text)+{+   // assume orthographic projection with units = screen pixels, origin at top left+   glEnable(GL_TEXTURE_2D);+   glBindTexture(GL_TEXTURE_2D, ftex);+   glBegin(GL_QUADS);+   while (*text) {+      if (*text >= 32 && *text < 128) {+         stbtt_aligned_quad q;+         stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9+         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);+         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);+         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);+         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);+      }+      ++text;+   }+   glEnd();+}+#endif+//+//+//////////////////////////////////////////////////////////////////////////////+//+// Complete program (this compiles): get a single bitmap, print as ASCII art+//+#if 0+#include <stdio.h>+#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation+#include "stb_truetype.h"++char ttf_buffer[1<<25];++int main(int argc, char **argv)+{+   stbtt_fontinfo font;+   unsigned char *bitmap;+   int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);++   fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));++   stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));+   bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);++   for (j=0; j < h; ++j) {+      for (i=0; i < w; ++i)+         putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);+      putchar('\n');+   }+   return 0;+}+#endif+//+// Output:+//+//     .ii.+//    @@@@@@.+//   V@Mio@@o+//   :i.  V@V+//     :oM@@M+//   :@@@MM@M+//   @@o  o@M+//  :@@.  M@M+//   @@@o@@@@+//   :M@@V:@@.+//+//////////////////////////////////////////////////////////////////////////////+//+// Complete program: print "Hello World!" banner, with bugs+//+#if 0+char buffer[24<<20];+unsigned char screen[20][79];++int main(int arg, char **argv)+{+   stbtt_fontinfo font;+   int i,j,ascent,baseline,ch=0;+   float scale, xpos=2; // leave a little padding in case the character extends left+   char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness++   fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));+   stbtt_InitFont(&font, buffer, 0);++   scale = stbtt_ScaleForPixelHeight(&font, 15);+   stbtt_GetFontVMetrics(&font, &ascent,0,0);+   baseline = (int) (ascent*scale);++   while (text[ch]) {+      int advance,lsb,x0,y0,x1,y1;+      float x_shift = xpos - (float) floor(xpos);+      stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);+      stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);+      stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);+      // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong+      // because this API is really for baking character bitmaps into textures. if you want to render+      // a sequence of characters, you really need to render each bitmap to a temp buffer, then+      // "alpha blend" that into the working buffer+      xpos += (advance * scale);+      if (text[ch+1])+         xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);+      ++ch;+   }++   for (j=0; j < 20; ++j) {+      for (i=0; i < 78; ++i)+         putchar(" .:ioVM@"[screen[j][i]>>5]);+      putchar('\n');+   }++   return 0;+}+#endif+++//////////////////////////////////////////////////////////////////////////////+//////////////////////////////////////////////////////////////////////////////+////+////   INTEGRATION WITH YOUR CODEBASE+////+////   The following sections allow you to supply alternate definitions+////   of C library functions used by stb_truetype, e.g. if you don't+////   link with the C runtime library.++#ifdef STB_TRUETYPE_IMPLEMENTATION+   // #define your own (u)stbtt_int8/16/32 before including to override this+   #ifndef stbtt_uint8+   typedef unsigned char   stbtt_uint8;+   typedef signed   char   stbtt_int8;+   typedef unsigned short  stbtt_uint16;+   typedef signed   short  stbtt_int16;+   typedef unsigned int    stbtt_uint32;+   typedef signed   int    stbtt_int32;+   #endif++   typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];+   typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];++   // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h+   #ifndef STBTT_ifloor+   #include <math.h>+   #define STBTT_ifloor(x)   ((int) floor(x))+   #define STBTT_iceil(x)    ((int) ceil(x))+   #endif++   #ifndef STBTT_sqrt+   #include <math.h>+   #define STBTT_sqrt(x)      sqrt(x)+   #define STBTT_pow(x,y)     pow(x,y)+   #endif++   #ifndef STBTT_fmod+   #include <math.h>+   #define STBTT_fmod(x,y)    fmod(x,y)+   #endif++   #ifndef STBTT_cos+   #include <math.h>+   #define STBTT_cos(x)       cos(x)+   #define STBTT_acos(x)      acos(x)+   #endif++   #ifndef STBTT_fabs+   #include <math.h>+   #define STBTT_fabs(x)      fabs(x)+   #endif++   // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h+   #ifndef STBTT_malloc+   #include <stdlib.h>+   #define STBTT_malloc(x,u)  ((void)(u),malloc(x))+   #define STBTT_free(x,u)    ((void)(u),free(x))+   #endif++   #ifndef STBTT_assert+   #include <assert.h>+   #define STBTT_assert(x)    assert(x)+   #endif++   #ifndef STBTT_strlen+   #include <string.h>+   #define STBTT_strlen(x)    strlen(x)+   #endif++   #ifndef STBTT_memcpy+   #include <string.h>+   #define STBTT_memcpy       memcpy+   #define STBTT_memset       memset+   #endif+#endif++///////////////////////////////////////////////////////////////////////////////+///////////////////////////////////////////////////////////////////////////////+////+////   INTERFACE+////+////++#ifndef __STB_INCLUDE_STB_TRUETYPE_H__+#define __STB_INCLUDE_STB_TRUETYPE_H__++#ifdef STBTT_STATIC+#define STBTT_DEF static+#else+#define STBTT_DEF extern+#endif++#ifdef __cplusplus+extern "C" {+#endif++// private structure+typedef struct+{+   unsigned char *data;+   int cursor;+   int size;+} stbtt__buf;++//////////////////////////////////////////////////////////////////////////////+//+// TEXTURE BAKING API+//+// If you use this API, you only have to call two functions ever.+//++typedef struct+{+   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap+   float xoff,yoff,xadvance;+} stbtt_bakedchar;++STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)+                                float pixel_height,                     // height of font in pixels+                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in+                                int first_char, int num_chars,          // characters to bake+                                stbtt_bakedchar *chardata);             // you allocate this, it's num_chars long+// if return is positive, the first unused row of the bitmap+// if return is negative, returns the negative of the number of characters that fit+// if return is 0, no characters fit and no rows were used+// This uses a very crappy packing.++typedef struct+{+   float x0,y0,s0,t0; // top-left+   float x1,y1,s1,t1; // bottom-right+} stbtt_aligned_quad;++STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph,  // same data as above+                               int char_index,             // character to display+                               float *xpos, float *ypos,   // pointers to current position in screen pixel space+                               stbtt_aligned_quad *q,      // output: quad to draw+                               int opengl_fillrule);       // true if opengl fill rule; false if DX9 or earlier+// Call GetBakedQuad with char_index = 'character - first_char', and it+// creates the quad you need to draw and advances the current position.+//+// The coordinate system used assumes y increases downwards.+//+// Characters will extend both above and below the current position;+// see discussion of "BASELINE" above.+//+// It's inefficient; you might want to c&p it and optimize it.++STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);+// Query the font vertical metrics without having to create a font first.+++//////////////////////////////////////////////////////////////////////////////+//+// NEW TEXTURE BAKING API+//+// This provides options for packing multiple fonts into one atlas, not+// perfectly but better than nothing.++typedef struct+{+   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap+   float xoff,yoff,xadvance;+   float xoff2,yoff2;+} stbtt_packedchar;++typedef struct stbtt_pack_context stbtt_pack_context;+typedef struct stbtt_fontinfo stbtt_fontinfo;+#ifndef STB_RECT_PACK_VERSION+typedef struct stbrp_rect stbrp_rect;+#endif++STBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);+// Initializes a packing context stored in the passed-in stbtt_pack_context.+// Future calls using this context will pack characters into the bitmap passed+// in here: a 1-channel bitmap that is width * height. stride_in_bytes is+// the distance from one row to the next (or 0 to mean they are packed tightly+// together). "padding" is the amount of padding to leave between each+// character (normally you want '1' for bitmaps you'll use as textures with+// bilinear filtering).+//+// Returns 0 on failure, 1 on success.++STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc);+// Cleans up the packing context and frees all memory.++#define STBTT_POINT_SIZE(x)   (-(x))++STBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,+                                int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);+// Creates character bitmaps from the font_index'th font found in fontdata (use+// font_index=0 if you don't know what that is). It creates num_chars_in_range+// bitmaps for characters with unicode values starting at first_unicode_char_in_range+// and increasing. Data for how to render them is stored in chardata_for_range;+// pass these to stbtt_GetPackedQuad to get back renderable quads.+//+// font_size is the full height of the character from ascender to descender,+// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed+// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()+// and pass that result as 'font_size':+//       ...,                  20 , ... // font max minus min y is 20 pixels tall+//       ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall++typedef struct+{+   float font_size;+   int first_unicode_codepoint_in_range;  // if non-zero, then the chars are continuous, and this is the first codepoint+   int *array_of_unicode_codepoints;       // if non-zero, then this is an array of unicode codepoints+   int num_chars;+   stbtt_packedchar *chardata_for_range; // output+   unsigned char h_oversample, v_oversample; // don't set these, they're used internally+} stbtt_pack_range;++STBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);+// Creates character bitmaps from multiple ranges of characters stored in+// ranges. This will usually create a better-packed bitmap than multiple+// calls to stbtt_PackFontRange. Note that you can call this multiple+// times within a single PackBegin/PackEnd.++STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);+// Oversampling a font increases the quality by allowing higher-quality subpixel+// positioning, and is especially valuable at smaller text sizes.+//+// This function sets the amount of oversampling for all following calls to+// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given+// pack context. The default (no oversampling) is achieved by h_oversample=1+// and v_oversample=1. The total number of pixels required is+// h_oversample*v_oversample larger than the default; for example, 2x2+// oversampling requires 4x the storage of 1x1. For best results, render+// oversampled textures with bilinear filtering. Look at the readme in+// stb/tests/oversample for information about oversampled fonts+//+// To use with PackFontRangesGather etc., you must set it before calls+// call to PackFontRangesGatherRects.++STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);+// If skip != 0, this tells stb_truetype to skip any codepoints for which+// there is no corresponding glyph. If skip=0, which is the default, then+// codepoints without a glyph recived the font's "missing character" glyph,+// typically an empty box by convention.++STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph,  // same data as above+                               int char_index,             // character to display+                               float *xpos, float *ypos,   // pointers to current position in screen pixel space+                               stbtt_aligned_quad *q,      // output: quad to draw+                               int align_to_integer);++STBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);+STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);+STBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);+// Calling these functions in sequence is roughly equivalent to calling+// stbtt_PackFontRanges(). If you more control over the packing of multiple+// fonts, or if you want to pack custom data into a font texture, take a look+// at the source to of stbtt_PackFontRanges() and create a custom version+// using these functions, e.g. call GatherRects multiple times,+// building up a single array of rects, then call PackRects once,+// then call RenderIntoRects repeatedly. This may result in a+// better packing than calling PackFontRanges multiple times+// (or it may not).++// this is an opaque structure that you shouldn't mess with which holds+// all the context needed from PackBegin to PackEnd.+struct stbtt_pack_context {+   void *user_allocator_context;+   void *pack_info;+   int   width;+   int   height;+   int   stride_in_bytes;+   int   padding;+   int   skip_missing;+   unsigned int   h_oversample, v_oversample;+   unsigned char *pixels;+   void  *nodes;+};++//////////////////////////////////////////////////////////////////////////////+//+// FONT LOADING+//+//++STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);+// This function will determine the number of fonts in a font file.  TrueType+// collection (.ttc) files may contain multiple fonts, while TrueType font+// (.ttf) files only contain one font. The number of fonts can be used for+// indexing with the previous function where the index is between zero and one+// less than the total fonts. If an error occurs, -1 is returned.++STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);+// Each .ttf/.ttc file may have more than one font. Each font has a sequential+// index number starting from 0. Call this function to get the font offset for+// a given index; it returns -1 if the index is out of range. A regular .ttf+// file will only define one font and it always be at offset 0, so it will+// return '0' for index 0, and -1 for all other indices.++// The following structure is defined publicly so you can declare one on+// the stack or as a global or etc, but you should treat it as opaque.+struct stbtt_fontinfo+{+   void           * userdata;+   unsigned char  * data;              // pointer to .ttf file+   int              fontstart;         // offset of start of font++   int numGlyphs;                     // number of glyphs, needed for range checking++   int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf+   int index_map;                     // a cmap mapping for our chosen character encoding+   int indexToLocFormat;              // format needed to map from glyph index to glyph++   stbtt__buf cff;                    // cff font data+   stbtt__buf charstrings;            // the charstring index+   stbtt__buf gsubrs;                 // global charstring subroutines index+   stbtt__buf subrs;                  // private charstring subroutines index+   stbtt__buf fontdicts;              // array of font dicts+   stbtt__buf fdselect;               // map from glyph to fontdict+};++STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);+// Given an offset into the file that defines a font, this function builds+// the necessary cached info for the rest of the system. You must allocate+// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't+// need to do anything special to free it, because the contents are pure+// value data with no additional data structures. Returns 0 on failure.+++//////////////////////////////////////////////////////////////////////////////+//+// CHARACTER TO GLYPH-INDEX CONVERSIOn++STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);+// If you're going to perform multiple operations on the same character+// and you want a speed-up, call this function with the character you're+// going to process, then use glyph-based functions instead of the+// codepoint-based functions.+// Returns 0 if the character codepoint is not defined in the font.+++//////////////////////////////////////////////////////////////////////////////+//+// CHARACTER PROPERTIES+//++STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);+// computes a scale factor to produce a font whose "height" is 'pixels' tall.+// Height is measured as the distance from the highest ascender to the lowest+// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics+// and computing:+//       scale = pixels / (ascent - descent)+// so if you prefer to measure height by the ascent only, use a similar calculation.++STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);+// computes a scale factor to produce a font whose EM size is mapped to+// 'pixels' tall. This is probably what traditional APIs compute, but+// I'm not positive.++STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);+// ascent is the coordinate above the baseline the font extends; descent+// is the coordinate below the baseline the font extends (i.e. it is typically negative)+// lineGap is the spacing between one row's descent and the next row's ascent...+// so you should advance the vertical position by "*ascent - *descent + *lineGap"+//   these are expressed in unscaled coordinates, so you must multiply by+//   the scale factor for a given size++STBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);+// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2+// table (specific to MS/Windows TTF files).+//+// Returns 1 on success (table present), 0 on failure.++STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);+// the bounding box around all possible characters++STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);+// leftSideBearing is the offset from the current horizontal position to the left edge of the character+// advanceWidth is the offset from the current horizontal position to the next horizontal position+//   these are expressed in unscaled coordinates++STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);+// an additional amount to add to the 'advance' value between ch1 and ch2++STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);+// Gets the bounding box of the visible part of the glyph, in unscaled coordinates++STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);+STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);+STBTT_DEF int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);+// as above, but takes one or more glyph indices for greater efficiency++typedef struct stbtt_kerningentry+{+   int glyph1; // use stbtt_FindGlyphIndex+   int glyph2;+   int advance;+} stbtt_kerningentry;++STBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info);+STBTT_DEF int  stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);+// Retrieves a complete list of all of the kerning pairs provided by the font+// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write.+// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1)++//////////////////////////////////////////////////////////////////////////////+//+// GLYPH SHAPES (you probably don't need these, but they have to go before+// the bitmaps for C declaration-order reasons)+//++#ifndef STBTT_vmove // you can predefine these to use different values (but why?)+   enum {+      STBTT_vmove=1,+      STBTT_vline,+      STBTT_vcurve,+      STBTT_vcubic+   };+#endif++#ifndef stbtt_vertex // you can predefine this to use different values+                   // (we share this with other code at RAD)+   #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file+   typedef struct+   {+      stbtt_vertex_type x,y,cx,cy,cx1,cy1;+      unsigned char type,padding;+   } stbtt_vertex;+#endif++STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);+// returns non-zero if nothing is drawn for this glyph++STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);+STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);+// returns # of vertices and fills *vertices with the pointer to them+//   these are expressed in "unscaled" coordinates+//+// The shape is a series of contours. Each one starts with+// a STBTT_moveto, then consists of a series of mixed+// STBTT_lineto and STBTT_curveto segments. A lineto+// draws a line from previous endpoint to its x,y; a curveto+// draws a quadratic bezier from previous endpoint to+// its x,y, using cx,cy as the bezier control point.++STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);+// frees the data allocated above++STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);+STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);+// fills svg with the character's SVG data.+// returns data size or 0 if SVG not found.++//////////////////////////////////////////////////////////////////////////////+//+// BITMAP RENDERING+//++STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);+// frees the bitmap allocated below++STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);+// allocates a large-enough single-channel 8bpp bitmap and renders the+// specified character/glyph at the specified scale into it, with+// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).+// *width & *height are filled out with the width & height of the bitmap,+// which is stored left-to-right, top-to-bottom.+//+// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap++STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);+// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel+// shift for the character++STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);+// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap+// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap+// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the+// width and height and positioning info for it first.++STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);+// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel+// shift for the character++STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);+// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering+// is performed (see stbtt_PackSetOversampling)++STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);+// get the bbox of the bitmap centered around the glyph origin; so the+// bitmap width is ix1-ix0, height is iy1-iy0, and location to place+// the bitmap top left is (leftSideBearing*scale,iy0).+// (Note that the bitmap uses y-increases-down, but the shape uses+// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)++STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);+// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel+// shift for the character++// the following functions are equivalent to the above functions, but operate+// on glyph indices instead of Unicode codepoints (for efficiency)+STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);+STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);+STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);+STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);+STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);+STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);+STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);+++// @TODO: don't expose this structure+typedef struct+{+   int w,h,stride;+   unsigned char *pixels;+} stbtt__bitmap;++// rasterize a shape with quadratic beziers into a bitmap+STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result,        // 1-channel bitmap to draw into+                               float flatness_in_pixels,     // allowable error of curve in pixels+                               stbtt_vertex *vertices,       // array of vertices defining shape+                               int num_verts,                // number of vertices in above array+                               float scale_x, float scale_y, // scale applied to input vertices+                               float shift_x, float shift_y, // translation applied to input vertices+                               int x_off, int y_off,         // another translation applied to input+                               int invert,                   // if non-zero, vertically flip shape+                               void *userdata);              // context for to STBTT_MALLOC++//////////////////////////////////////////////////////////////////////////////+//+// Signed Distance Function (or Field) rendering++STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);+// frees the SDF bitmap allocated below++STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);+STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);+// These functions compute a discretized SDF field for a single character, suitable for storing+// in a single-channel texture, sampling with bilinear filtering, and testing against+// larger than some threshold to produce scalable fonts.+//        info              --  the font+//        scale             --  controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap+//        glyph/codepoint   --  the character to generate the SDF for+//        padding           --  extra "pixels" around the character which are filled with the distance to the character (not 0),+//                                 which allows effects like bit outlines+//        onedge_value      --  value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)+//        pixel_dist_scale  --  what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)+//                                 if positive, > onedge_value is inside; if negative, < onedge_value is inside+//        width,height      --  output height & width of the SDF bitmap (including padding)+//        xoff,yoff         --  output origin of the character+//        return value      --  a 2D array of bytes 0..255, width*height in size+//+// pixel_dist_scale & onedge_value are a scale & bias that allows you to make+// optimal use of the limited 0..255 for your application, trading off precision+// and special effects. SDF values outside the range 0..255 are clamped to 0..255.+//+// Example:+//      scale = stbtt_ScaleForPixelHeight(22)+//      padding = 5+//      onedge_value = 180+//      pixel_dist_scale = 180/5.0 = 36.0+//+//      This will create an SDF bitmap in which the character is about 22 pixels+//      high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled+//      shape, sample the SDF at each pixel and fill the pixel if the SDF value+//      is greater than or equal to 180/255. (You'll actually want to antialias,+//      which is beyond the scope of this example.) Additionally, you can compute+//      offset outlines (e.g. to stroke the character border inside & outside,+//      or only outside). For example, to fill outside the character up to 3 SDF+//      pixels, you would compare against (180-36.0*3)/255 = 72/255. The above+//      choice of variables maps a range from 5 pixels outside the shape to+//      2 pixels inside the shape to 0..255; this is intended primarily for apply+//      outside effects only (the interior range is needed to allow proper+//      antialiasing of the font at *smaller* sizes)+//+// The function computes the SDF analytically at each SDF pixel, not by e.g.+// building a higher-res bitmap and approximating it. In theory the quality+// should be as high as possible for an SDF of this size & representation, but+// unclear if this is true in practice (perhaps building a higher-res bitmap+// and computing from that can allow drop-out prevention).+//+// The algorithm has not been optimized at all, so expect it to be slow+// if computing lots of characters or very large sizes.++++//////////////////////////////////////////////////////////////////////////////+//+// Finding the right font...+//+// You should really just solve this offline, keep your own tables+// of what font is what, and don't try to get it out of the .ttf file.+// That's because getting it out of the .ttf file is really hard, because+// the names in the file can appear in many possible encodings, in many+// possible languages, and e.g. if you need a case-insensitive comparison,+// the details of that depend on the encoding & language in a complex way+// (actually underspecified in truetype, but also gigantic).+//+// But you can use the provided functions in two possible ways:+//     stbtt_FindMatchingFont() will use *case-sensitive* comparisons on+//             unicode-encoded names to try to find the font you want;+//             you can run this before calling stbtt_InitFont()+//+//     stbtt_GetFontNameString() lets you get any of the various strings+//             from the file yourself and do your own comparisons on them.+//             You have to have called stbtt_InitFont() first.+++STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);+// returns the offset (not index) of the font that matches, or -1 if none+//   if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".+//   if you use any other flag, use a font name like "Arial"; this checks+//     the 'macStyle' header field; i don't know if fonts set this consistently+#define STBTT_MACSTYLE_DONTCARE     0+#define STBTT_MACSTYLE_BOLD         1+#define STBTT_MACSTYLE_ITALIC       2+#define STBTT_MACSTYLE_UNDERSCORE   4+#define STBTT_MACSTYLE_NONE         8   // <= not same as 0, this makes us check the bitfield is 0++STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);+// returns 1/0 whether the first string interpreted as utf8 is identical to+// the second string interpreted as big-endian utf16... useful for strings from next func++STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);+// returns the string (which may be big-endian double byte, e.g. for unicode)+// and puts the length in bytes in *length.+//+// some of the values for the IDs are below; for more see the truetype spec:+//     http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html+//     http://www.microsoft.com/typography/otspec/name.htm++enum { // platformID+   STBTT_PLATFORM_ID_UNICODE   =0,+   STBTT_PLATFORM_ID_MAC       =1,+   STBTT_PLATFORM_ID_ISO       =2,+   STBTT_PLATFORM_ID_MICROSOFT =3+};++enum { // encodingID for STBTT_PLATFORM_ID_UNICODE+   STBTT_UNICODE_EID_UNICODE_1_0    =0,+   STBTT_UNICODE_EID_UNICODE_1_1    =1,+   STBTT_UNICODE_EID_ISO_10646      =2,+   STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,+   STBTT_UNICODE_EID_UNICODE_2_0_FULL=4+};++enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT+   STBTT_MS_EID_SYMBOL        =0,+   STBTT_MS_EID_UNICODE_BMP   =1,+   STBTT_MS_EID_SHIFTJIS      =2,+   STBTT_MS_EID_UNICODE_FULL  =10+};++enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes+   STBTT_MAC_EID_ROMAN        =0,   STBTT_MAC_EID_ARABIC       =4,+   STBTT_MAC_EID_JAPANESE     =1,   STBTT_MAC_EID_HEBREW       =5,+   STBTT_MAC_EID_CHINESE_TRAD =2,   STBTT_MAC_EID_GREEK        =6,+   STBTT_MAC_EID_KOREAN       =3,   STBTT_MAC_EID_RUSSIAN      =7+};++enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...+       // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs+   STBTT_MS_LANG_ENGLISH     =0x0409,   STBTT_MS_LANG_ITALIAN     =0x0410,+   STBTT_MS_LANG_CHINESE     =0x0804,   STBTT_MS_LANG_JAPANESE    =0x0411,+   STBTT_MS_LANG_DUTCH       =0x0413,   STBTT_MS_LANG_KOREAN      =0x0412,+   STBTT_MS_LANG_FRENCH      =0x040c,   STBTT_MS_LANG_RUSSIAN     =0x0419,+   STBTT_MS_LANG_GERMAN      =0x0407,   STBTT_MS_LANG_SPANISH     =0x0409,+   STBTT_MS_LANG_HEBREW      =0x040d,   STBTT_MS_LANG_SWEDISH     =0x041D+};++enum { // languageID for STBTT_PLATFORM_ID_MAC+   STBTT_MAC_LANG_ENGLISH      =0 ,   STBTT_MAC_LANG_JAPANESE     =11,+   STBTT_MAC_LANG_ARABIC       =12,   STBTT_MAC_LANG_KOREAN       =23,+   STBTT_MAC_LANG_DUTCH        =4 ,   STBTT_MAC_LANG_RUSSIAN      =32,+   STBTT_MAC_LANG_FRENCH       =1 ,   STBTT_MAC_LANG_SPANISH      =6 ,+   STBTT_MAC_LANG_GERMAN       =2 ,   STBTT_MAC_LANG_SWEDISH      =5 ,+   STBTT_MAC_LANG_HEBREW       =10,   STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,+   STBTT_MAC_LANG_ITALIAN      =3 ,   STBTT_MAC_LANG_CHINESE_TRAD =19+};++#ifdef __cplusplus+}+#endif++#endif // __STB_INCLUDE_STB_TRUETYPE_H__++///////////////////////////////////////////////////////////////////////////////+///////////////////////////////////////////////////////////////////////////////+////+////   IMPLEMENTATION+////+////++#ifdef STB_TRUETYPE_IMPLEMENTATION++#ifndef STBTT_MAX_OVERSAMPLE+#define STBTT_MAX_OVERSAMPLE   8+#endif++#if STBTT_MAX_OVERSAMPLE > 255+#error "STBTT_MAX_OVERSAMPLE cannot be > 255"+#endif++typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];++#ifndef STBTT_RASTERIZER_VERSION+#define STBTT_RASTERIZER_VERSION 2+#endif++#ifdef _MSC_VER+#define STBTT__NOTUSED(v)  (void)(v)+#else+#define STBTT__NOTUSED(v)  (void)sizeof(v)+#endif++//////////////////////////////////////////////////////////////////////////+//+// stbtt__buf helpers to parse data from file+//++static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)+{+   if (b->cursor >= b->size)+      return 0;+   return b->data[b->cursor++];+}++static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)+{+   if (b->cursor >= b->size)+      return 0;+   return b->data[b->cursor];+}++static void stbtt__buf_seek(stbtt__buf *b, int o)+{+   STBTT_assert(!(o > b->size || o < 0));+   b->cursor = (o > b->size || o < 0) ? b->size : o;+}++static void stbtt__buf_skip(stbtt__buf *b, int o)+{+   stbtt__buf_seek(b, b->cursor + o);+}++static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)+{+   stbtt_uint32 v = 0;+   int i;+   STBTT_assert(n >= 1 && n <= 4);+   for (i = 0; i < n; i++)+      v = (v << 8) | stbtt__buf_get8(b);+   return v;+}++static stbtt__buf stbtt__new_buf(const void *p, size_t size)+{+   stbtt__buf r;+   STBTT_assert(size < 0x40000000);+   r.data = (stbtt_uint8*) p;+   r.size = (int) size;+   r.cursor = 0;+   return r;+}++#define stbtt__buf_get16(b)  stbtt__buf_get((b), 2)+#define stbtt__buf_get32(b)  stbtt__buf_get((b), 4)++static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)+{+   stbtt__buf r = stbtt__new_buf(NULL, 0);+   if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;+   r.data = b->data + o;+   r.size = s;+   return r;+}++static stbtt__buf stbtt__cff_get_index(stbtt__buf *b)+{+   int count, start, offsize;+   start = b->cursor;+   count = stbtt__buf_get16(b);+   if (count) {+      offsize = stbtt__buf_get8(b);+      STBTT_assert(offsize >= 1 && offsize <= 4);+      stbtt__buf_skip(b, offsize * count);+      stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);+   }+   return stbtt__buf_range(b, start, b->cursor - start);+}++static stbtt_uint32 stbtt__cff_int(stbtt__buf *b)+{+   int b0 = stbtt__buf_get8(b);+   if (b0 >= 32 && b0 <= 246)       return b0 - 139;+   else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;+   else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;+   else if (b0 == 28)               return stbtt__buf_get16(b);+   else if (b0 == 29)               return stbtt__buf_get32(b);+   STBTT_assert(0);+   return 0;+}++static void stbtt__cff_skip_operand(stbtt__buf *b) {+   int v, b0 = stbtt__buf_peek8(b);+   STBTT_assert(b0 >= 28);+   if (b0 == 30) {+      stbtt__buf_skip(b, 1);+      while (b->cursor < b->size) {+         v = stbtt__buf_get8(b);+         if ((v & 0xF) == 0xF || (v >> 4) == 0xF)+            break;+      }+   } else {+      stbtt__cff_int(b);+   }+}++static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)+{+   stbtt__buf_seek(b, 0);+   while (b->cursor < b->size) {+      int start = b->cursor, end, op;+      while (stbtt__buf_peek8(b) >= 28)+         stbtt__cff_skip_operand(b);+      end = b->cursor;+      op = stbtt__buf_get8(b);+      if (op == 12)  op = stbtt__buf_get8(b) | 0x100;+      if (op == key) return stbtt__buf_range(b, start, end-start);+   }+   return stbtt__buf_range(b, 0, 0);+}++static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)+{+   int i;+   stbtt__buf operands = stbtt__dict_get(b, key);+   for (i = 0; i < outcount && operands.cursor < operands.size; i++)+      out[i] = stbtt__cff_int(&operands);+}++static int stbtt__cff_index_count(stbtt__buf *b)+{+   stbtt__buf_seek(b, 0);+   return stbtt__buf_get16(b);+}++static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)+{+   int count, offsize, start, end;+   stbtt__buf_seek(&b, 0);+   count = stbtt__buf_get16(&b);+   offsize = stbtt__buf_get8(&b);+   STBTT_assert(i >= 0 && i < count);+   STBTT_assert(offsize >= 1 && offsize <= 4);+   stbtt__buf_skip(&b, i*offsize);+   start = stbtt__buf_get(&b, offsize);+   end = stbtt__buf_get(&b, offsize);+   return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);+}++//////////////////////////////////////////////////////////////////////////+//+// accessors to parse data from file+//++// on platforms that don't allow misaligned reads, if we want to allow+// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE++#define ttBYTE(p)     (* (stbtt_uint8 *) (p))+#define ttCHAR(p)     (* (stbtt_int8 *) (p))+#define ttFixed(p)    ttLONG(p)++static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }+static stbtt_int16 ttSHORT(stbtt_uint8 *p)   { return p[0]*256 + p[1]; }+static stbtt_uint32 ttULONG(stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }+static stbtt_int32 ttLONG(stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }++#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))+#define stbtt_tag(p,str)           stbtt_tag4(p,str[0],str[1],str[2],str[3])++static int stbtt__isfont(stbtt_uint8 *font)+{+   // check the version number+   if (stbtt_tag4(font, '1',0,0,0))  return 1; // TrueType 1+   if (stbtt_tag(font, "typ1"))   return 1; // TrueType with type 1 font -- we don't support this!+   if (stbtt_tag(font, "OTTO"))   return 1; // OpenType with CFF+   if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0+   if (stbtt_tag(font, "true"))   return 1; // Apple specification for TrueType fonts+   return 0;+}++// @OPTIMIZE: binary search+static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)+{+   stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);+   stbtt_uint32 tabledir = fontstart + 12;+   stbtt_int32 i;+   for (i=0; i < num_tables; ++i) {+      stbtt_uint32 loc = tabledir + 16*i;+      if (stbtt_tag(data+loc+0, tag))+         return ttULONG(data+loc+8);+   }+   return 0;+}++static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index)+{+   // if it's just a font, there's only one valid index+   if (stbtt__isfont(font_collection))+      return index == 0 ? 0 : -1;++   // check if it's a TTC+   if (stbtt_tag(font_collection, "ttcf")) {+      // version 1?+      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {+         stbtt_int32 n = ttLONG(font_collection+8);+         if (index >= n)+            return -1;+         return ttULONG(font_collection+12+index*4);+      }+   }+   return -1;+}++static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection)+{+   // if it's just a font, there's only one valid font+   if (stbtt__isfont(font_collection))+      return 1;++   // check if it's a TTC+   if (stbtt_tag(font_collection, "ttcf")) {+      // version 1?+      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {+         return ttLONG(font_collection+8);+      }+   }+   return 0;+}++static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)+{+   stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };+   stbtt__buf pdict;+   stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);+   if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);+   pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);+   stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);+   if (!subrsoff) return stbtt__new_buf(NULL, 0);+   stbtt__buf_seek(&cff, private_loc[1]+subrsoff);+   return stbtt__cff_get_index(&cff);+}++// since most people won't use this, find this table the first time it's needed+static int stbtt__get_svg(stbtt_fontinfo *info)+{+   stbtt_uint32 t;+   if (info->svg < 0) {+      t = stbtt__find_table(info->data, info->fontstart, "SVG ");+      if (t) {+         stbtt_uint32 offset = ttULONG(info->data + t + 2);+         info->svg = t + offset;+      } else {+         info->svg = 0;+      }+   }+   return info->svg;+}++static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)+{+   stbtt_uint32 cmap, t;+   stbtt_int32 i,numTables;++   info->data = data;+   info->fontstart = fontstart;+   info->cff = stbtt__new_buf(NULL, 0);++   cmap = stbtt__find_table(data, fontstart, "cmap");       // required+   info->loca = stbtt__find_table(data, fontstart, "loca"); // required+   info->head = stbtt__find_table(data, fontstart, "head"); // required+   info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required+   info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required+   info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required+   info->kern = stbtt__find_table(data, fontstart, "kern"); // not required+   info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required++   if (!cmap || !info->head || !info->hhea || !info->hmtx)+      return 0;+   if (info->glyf) {+      // required for truetype+      if (!info->loca) return 0;+   } else {+      // initialization for CFF / Type2 fonts (OTF)+      stbtt__buf b, topdict, topdictidx;+      stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;+      stbtt_uint32 cff;++      cff = stbtt__find_table(data, fontstart, "CFF ");+      if (!cff) return 0;++      info->fontdicts = stbtt__new_buf(NULL, 0);+      info->fdselect = stbtt__new_buf(NULL, 0);++      // @TODO this should use size from table (not 512MB)+      info->cff = stbtt__new_buf(data+cff, 512*1024*1024);+      b = info->cff;++      // read the header+      stbtt__buf_skip(&b, 2);+      stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize++      // @TODO the name INDEX could list multiple fonts,+      // but we just use the first one.+      stbtt__cff_get_index(&b);  // name INDEX+      topdictidx = stbtt__cff_get_index(&b);+      topdict = stbtt__cff_index_get(topdictidx, 0);+      stbtt__cff_get_index(&b);  // string INDEX+      info->gsubrs = stbtt__cff_get_index(&b);++      stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);+      stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);+      stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);+      stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);+      info->subrs = stbtt__get_subrs(b, topdict);++      // we only support Type 2 charstrings+      if (cstype != 2) return 0;+      if (charstrings == 0) return 0;++      if (fdarrayoff) {+         // looks like a CID font+         if (!fdselectoff) return 0;+         stbtt__buf_seek(&b, fdarrayoff);+         info->fontdicts = stbtt__cff_get_index(&b);+         info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);+      }++      stbtt__buf_seek(&b, charstrings);+      info->charstrings = stbtt__cff_get_index(&b);+   }++   t = stbtt__find_table(data, fontstart, "maxp");+   if (t)+      info->numGlyphs = ttUSHORT(data+t+4);+   else+      info->numGlyphs = 0xffff;++   info->svg = -1;++   // find a cmap encoding table we understand *now* to avoid searching+   // later. (todo: could make this installable)+   // the same regardless of glyph.+   numTables = ttUSHORT(data + cmap + 2);+   info->index_map = 0;+   for (i=0; i < numTables; ++i) {+      stbtt_uint32 encoding_record = cmap + 4 + 8 * i;+      // find an encoding we understand:+      switch(ttUSHORT(data+encoding_record)) {+         case STBTT_PLATFORM_ID_MICROSOFT:+            switch (ttUSHORT(data+encoding_record+2)) {+               case STBTT_MS_EID_UNICODE_BMP:+               case STBTT_MS_EID_UNICODE_FULL:+                  // MS/Unicode+                  info->index_map = cmap + ttULONG(data+encoding_record+4);+                  break;+            }+            break;+        case STBTT_PLATFORM_ID_UNICODE:+            // Mac/iOS has these+            // all the encodingIDs are unicode, so we don't bother to check it+            info->index_map = cmap + ttULONG(data+encoding_record+4);+            break;+      }+   }+   if (info->index_map == 0)+      return 0;++   info->indexToLocFormat = ttUSHORT(data+info->head + 50);+   return 1;+}++STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)+{+   stbtt_uint8 *data = info->data;+   stbtt_uint32 index_map = info->index_map;++   stbtt_uint16 format = ttUSHORT(data + index_map + 0);+   if (format == 0) { // apple byte encoding+      stbtt_int32 bytes = ttUSHORT(data + index_map + 2);+      if (unicode_codepoint < bytes-6)+         return ttBYTE(data + index_map + 6 + unicode_codepoint);+      return 0;+   } else if (format == 6) {+      stbtt_uint32 first = ttUSHORT(data + index_map + 6);+      stbtt_uint32 count = ttUSHORT(data + index_map + 8);+      if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)+         return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);+      return 0;+   } else if (format == 2) {+      STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean+      return 0;+   } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges+      stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;+      stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;+      stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);+      stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;++      // do a binary search of the segments+      stbtt_uint32 endCount = index_map + 14;+      stbtt_uint32 search = endCount;++      if (unicode_codepoint > 0xffff)+         return 0;++      // they lie from endCount .. endCount + segCount+      // but searchRange is the nearest power of two, so...+      if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))+         search += rangeShift*2;++      // now decrement to bias correctly to find smallest+      search -= 2;+      while (entrySelector) {+         stbtt_uint16 end;+         searchRange >>= 1;+         end = ttUSHORT(data + search + searchRange*2);+         if (unicode_codepoint > end)+            search += searchRange*2;+         --entrySelector;+      }+      search += 2;++      {+         stbtt_uint16 offset, start;+         stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);++         STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));+         start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);+         if (unicode_codepoint < start)+            return 0;++         offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);+         if (offset == 0)+            return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));++         return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);+      }+   } else if (format == 12 || format == 13) {+      stbtt_uint32 ngroups = ttULONG(data+index_map+12);+      stbtt_int32 low,high;+      low = 0; high = (stbtt_int32)ngroups;+      // Binary search the right group.+      while (low < high) {+         stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high+         stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);+         stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);+         if ((stbtt_uint32) unicode_codepoint < start_char)+            high = mid;+         else if ((stbtt_uint32) unicode_codepoint > end_char)+            low = mid+1;+         else {+            stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);+            if (format == 12)+               return start_glyph + unicode_codepoint-start_char;+            else // format == 13+               return start_glyph;+         }+      }+      return 0; // not found+   }+   // @TODO+   STBTT_assert(0);+   return 0;+}++STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)+{+   return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);+}++static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)+{+   v->type = type;+   v->x = (stbtt_int16) x;+   v->y = (stbtt_int16) y;+   v->cx = (stbtt_int16) cx;+   v->cy = (stbtt_int16) cy;+}++static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)+{+   int g1,g2;++   STBTT_assert(!info->cff.size);++   if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range+   if (info->indexToLocFormat >= 2)    return -1; // unknown index->glyph map format++   if (info->indexToLocFormat == 0) {+      g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;+      g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;+   } else {+      g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);+      g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);+   }++   return g1==g2 ? -1 : g1; // if length is 0, return -1+}++static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);++STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)+{+   if (info->cff.size) {+      stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);+   } else {+      int g = stbtt__GetGlyfOffset(info, glyph_index);+      if (g < 0) return 0;++      if (x0) *x0 = ttSHORT(info->data + g + 2);+      if (y0) *y0 = ttSHORT(info->data + g + 4);+      if (x1) *x1 = ttSHORT(info->data + g + 6);+      if (y1) *y1 = ttSHORT(info->data + g + 8);+   }+   return 1;+}++STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)+{+   return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);+}++STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)+{+   stbtt_int16 numberOfContours;+   int g;+   if (info->cff.size)+      return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;+   g = stbtt__GetGlyfOffset(info, glyph_index);+   if (g < 0) return 1;+   numberOfContours = ttSHORT(info->data + g);+   return numberOfContours == 0;+}++static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,+    stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)+{+   if (start_off) {+      if (was_off)+         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);+      stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);+   } else {+      if (was_off)+         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);+      else+         stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);+   }+   return num_vertices;+}++static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)+{+   stbtt_int16 numberOfContours;+   stbtt_uint8 *endPtsOfContours;+   stbtt_uint8 *data = info->data;+   stbtt_vertex *vertices=0;+   int num_vertices=0;+   int g = stbtt__GetGlyfOffset(info, glyph_index);++   *pvertices = NULL;++   if (g < 0) return 0;++   numberOfContours = ttSHORT(data + g);++   if (numberOfContours > 0) {+      stbtt_uint8 flags=0,flagcount;+      stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;+      stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;+      stbtt_uint8 *points;+      endPtsOfContours = (data + g + 10);+      ins = ttUSHORT(data + g + 10 + numberOfContours * 2);+      points = data + g + 10 + numberOfContours * 2 + 2 + ins;++      n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);++      m = n + 2*numberOfContours;  // a loose bound on how many vertices we might need+      vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);+      if (vertices == 0)+         return 0;++      next_move = 0;+      flagcount=0;++      // in first pass, we load uninterpreted data into the allocated array+      // above, shifted to the end of the array so we won't overwrite it when+      // we create our final data starting from the front++      off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated++      // first load flags++      for (i=0; i < n; ++i) {+         if (flagcount == 0) {+            flags = *points++;+            if (flags & 8)+               flagcount = *points++;+         } else+            --flagcount;+         vertices[off+i].type = flags;+      }++      // now load x coordinates+      x=0;+      for (i=0; i < n; ++i) {+         flags = vertices[off+i].type;+         if (flags & 2) {+            stbtt_int16 dx = *points++;+            x += (flags & 16) ? dx : -dx; // ???+         } else {+            if (!(flags & 16)) {+               x = x + (stbtt_int16) (points[0]*256 + points[1]);+               points += 2;+            }+         }+         vertices[off+i].x = (stbtt_int16) x;+      }++      // now load y coordinates+      y=0;+      for (i=0; i < n; ++i) {+         flags = vertices[off+i].type;+         if (flags & 4) {+            stbtt_int16 dy = *points++;+            y += (flags & 32) ? dy : -dy; // ???+         } else {+            if (!(flags & 32)) {+               y = y + (stbtt_int16) (points[0]*256 + points[1]);+               points += 2;+            }+         }+         vertices[off+i].y = (stbtt_int16) y;+      }++      // now convert them to our format+      num_vertices=0;+      sx = sy = cx = cy = scx = scy = 0;+      for (i=0; i < n; ++i) {+         flags = vertices[off+i].type;+         x     = (stbtt_int16) vertices[off+i].x;+         y     = (stbtt_int16) vertices[off+i].y;++         if (next_move == i) {+            if (i != 0)+               num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);++            // now start the new one+            start_off = !(flags & 1);+            if (start_off) {+               // if we start off with an off-curve point, then when we need to find a point on the curve+               // where we can start, and we need to save some state for when we wraparound.+               scx = x;+               scy = y;+               if (!(vertices[off+i+1].type & 1)) {+                  // next point is also a curve point, so interpolate an on-point curve+                  sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;+                  sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;+               } else {+                  // otherwise just use the next point as our start point+                  sx = (stbtt_int32) vertices[off+i+1].x;+                  sy = (stbtt_int32) vertices[off+i+1].y;+                  ++i; // we're using point i+1 as the starting point, so skip it+               }+            } else {+               sx = x;+               sy = y;+            }+            stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);+            was_off = 0;+            next_move = 1 + ttUSHORT(endPtsOfContours+j*2);+            ++j;+         } else {+            if (!(flags & 1)) { // if it's a curve+               if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint+                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);+               cx = x;+               cy = y;+               was_off = 1;+            } else {+               if (was_off)+                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);+               else+                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);+               was_off = 0;+            }+         }+      }+      num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);+   } else if (numberOfContours < 0) {+      // Compound shapes.+      int more = 1;+      stbtt_uint8 *comp = data + g + 10;+      num_vertices = 0;+      vertices = 0;+      while (more) {+         stbtt_uint16 flags, gidx;+         int comp_num_verts = 0, i;+         stbtt_vertex *comp_verts = 0, *tmp = 0;+         float mtx[6] = {1,0,0,1,0,0}, m, n;++         flags = ttSHORT(comp); comp+=2;+         gidx = ttSHORT(comp); comp+=2;++         if (flags & 2) { // XY values+            if (flags & 1) { // shorts+               mtx[4] = ttSHORT(comp); comp+=2;+               mtx[5] = ttSHORT(comp); comp+=2;+            } else {+               mtx[4] = ttCHAR(comp); comp+=1;+               mtx[5] = ttCHAR(comp); comp+=1;+            }+         }+         else {+            // @TODO handle matching point+            STBTT_assert(0);+         }+         if (flags & (1<<3)) { // WE_HAVE_A_SCALE+            mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;+            mtx[1] = mtx[2] = 0;+         } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE+            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;+            mtx[1] = mtx[2] = 0;+            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;+         } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO+            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;+            mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;+            mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;+            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;+         }++         // Find transformation scales.+         m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);+         n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);++         // Get indexed glyph.+         comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);+         if (comp_num_verts > 0) {+            // Transform vertices.+            for (i = 0; i < comp_num_verts; ++i) {+               stbtt_vertex* v = &comp_verts[i];+               stbtt_vertex_type x,y;+               x=v->x; y=v->y;+               v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));+               v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));+               x=v->cx; y=v->cy;+               v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));+               v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));+            }+            // Append vertices.+            tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);+            if (!tmp) {+               if (vertices) STBTT_free(vertices, info->userdata);+               if (comp_verts) STBTT_free(comp_verts, info->userdata);+               return 0;+            }+            if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));+            STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));+            if (vertices) STBTT_free(vertices, info->userdata);+            vertices = tmp;+            STBTT_free(comp_verts, info->userdata);+            num_vertices += comp_num_verts;+         }+         // More components ?+         more = flags & (1<<5);+      }+   } else {+      // numberOfCounters == 0, do nothing+   }++   *pvertices = vertices;+   return num_vertices;+}++typedef struct+{+   int bounds;+   int started;+   float first_x, first_y;+   float x, y;+   stbtt_int32 min_x, max_x, min_y, max_y;++   stbtt_vertex *pvertices;+   int num_vertices;+} stbtt__csctx;++#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}++static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)+{+   if (x > c->max_x || !c->started) c->max_x = x;+   if (y > c->max_y || !c->started) c->max_y = y;+   if (x < c->min_x || !c->started) c->min_x = x;+   if (y < c->min_y || !c->started) c->min_y = y;+   c->started = 1;+}++static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1)+{+   if (c->bounds) {+      stbtt__track_vertex(c, x, y);+      if (type == STBTT_vcubic) {+         stbtt__track_vertex(c, cx, cy);+         stbtt__track_vertex(c, cx1, cy1);+      }+   } else {+      stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);+      c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;+      c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;+   }+   c->num_vertices++;+}++static void stbtt__csctx_close_shape(stbtt__csctx *ctx)+{+   if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)+      stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);+}++static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)+{+   stbtt__csctx_close_shape(ctx);+   ctx->first_x = ctx->x = ctx->x + dx;+   ctx->first_y = ctx->y = ctx->y + dy;+   stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);+}++static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)+{+   ctx->x += dx;+   ctx->y += dy;+   stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);+}++static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)+{+   float cx1 = ctx->x + dx1;+   float cy1 = ctx->y + dy1;+   float cx2 = cx1 + dx2;+   float cy2 = cy1 + dy2;+   ctx->x = cx2 + dx3;+   ctx->y = cy2 + dy3;+   stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);+}++static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)+{+   int count = stbtt__cff_index_count(&idx);+   int bias = 107;+   if (count >= 33900)+      bias = 32768;+   else if (count >= 1240)+      bias = 1131;+   n += bias;+   if (n < 0 || n >= count)+      return stbtt__new_buf(NULL, 0);+   return stbtt__cff_index_get(idx, n);+}++static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)+{+   stbtt__buf fdselect = info->fdselect;+   int nranges, start, end, v, fmt, fdselector = -1, i;++   stbtt__buf_seek(&fdselect, 0);+   fmt = stbtt__buf_get8(&fdselect);+   if (fmt == 0) {+      // untested+      stbtt__buf_skip(&fdselect, glyph_index);+      fdselector = stbtt__buf_get8(&fdselect);+   } else if (fmt == 3) {+      nranges = stbtt__buf_get16(&fdselect);+      start = stbtt__buf_get16(&fdselect);+      for (i = 0; i < nranges; i++) {+         v = stbtt__buf_get8(&fdselect);+         end = stbtt__buf_get16(&fdselect);+         if (glyph_index >= start && glyph_index < end) {+            fdselector = v;+            break;+         }+         start = end;+      }+   }+   if (fdselector == -1) stbtt__new_buf(NULL, 0);+   return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));+}++static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)+{+   int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;+   int has_subrs = 0, clear_stack;+   float s[48];+   stbtt__buf subr_stack[10], subrs = info->subrs, b;+   float f;++#define STBTT__CSERR(s) (0)++   // this currently ignores the initial width value, which isn't needed if we have hmtx+   b = stbtt__cff_index_get(info->charstrings, glyph_index);+   while (b.cursor < b.size) {+      i = 0;+      clear_stack = 1;+      b0 = stbtt__buf_get8(&b);+      switch (b0) {+      // @TODO implement hinting+      case 0x13: // hintmask+      case 0x14: // cntrmask+         if (in_header)+            maskbits += (sp / 2); // implicit "vstem"+         in_header = 0;+         stbtt__buf_skip(&b, (maskbits + 7) / 8);+         break;++      case 0x01: // hstem+      case 0x03: // vstem+      case 0x12: // hstemhm+      case 0x17: // vstemhm+         maskbits += (sp / 2);+         break;++      case 0x15: // rmoveto+         in_header = 0;+         if (sp < 2) return STBTT__CSERR("rmoveto stack");+         stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);+         break;+      case 0x04: // vmoveto+         in_header = 0;+         if (sp < 1) return STBTT__CSERR("vmoveto stack");+         stbtt__csctx_rmove_to(c, 0, s[sp-1]);+         break;+      case 0x16: // hmoveto+         in_header = 0;+         if (sp < 1) return STBTT__CSERR("hmoveto stack");+         stbtt__csctx_rmove_to(c, s[sp-1], 0);+         break;++      case 0x05: // rlineto+         if (sp < 2) return STBTT__CSERR("rlineto stack");+         for (; i + 1 < sp; i += 2)+            stbtt__csctx_rline_to(c, s[i], s[i+1]);+         break;++      // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical+      // starting from a different place.++      case 0x07: // vlineto+         if (sp < 1) return STBTT__CSERR("vlineto stack");+         goto vlineto;+      case 0x06: // hlineto+         if (sp < 1) return STBTT__CSERR("hlineto stack");+         for (;;) {+            if (i >= sp) break;+            stbtt__csctx_rline_to(c, s[i], 0);+            i++;+      vlineto:+            if (i >= sp) break;+            stbtt__csctx_rline_to(c, 0, s[i]);+            i++;+         }+         break;++      case 0x1F: // hvcurveto+         if (sp < 4) return STBTT__CSERR("hvcurveto stack");+         goto hvcurveto;+      case 0x1E: // vhcurveto+         if (sp < 4) return STBTT__CSERR("vhcurveto stack");+         for (;;) {+            if (i + 3 >= sp) break;+            stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);+            i += 4;+      hvcurveto:+            if (i + 3 >= sp) break;+            stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);+            i += 4;+         }+         break;++      case 0x08: // rrcurveto+         if (sp < 6) return STBTT__CSERR("rcurveline stack");+         for (; i + 5 < sp; i += 6)+            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);+         break;++      case 0x18: // rcurveline+         if (sp < 8) return STBTT__CSERR("rcurveline stack");+         for (; i + 5 < sp - 2; i += 6)+            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);+         if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");+         stbtt__csctx_rline_to(c, s[i], s[i+1]);+         break;++      case 0x19: // rlinecurve+         if (sp < 8) return STBTT__CSERR("rlinecurve stack");+         for (; i + 1 < sp - 6; i += 2)+            stbtt__csctx_rline_to(c, s[i], s[i+1]);+         if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");+         stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);+         break;++      case 0x1A: // vvcurveto+      case 0x1B: // hhcurveto+         if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");+         f = 0.0;+         if (sp & 1) { f = s[i]; i++; }+         for (; i + 3 < sp; i += 4) {+            if (b0 == 0x1B)+               stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);+            else+               stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);+            f = 0.0;+         }+         break;++      case 0x0A: // callsubr+         if (!has_subrs) {+            if (info->fdselect.size)+               subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);+            has_subrs = 1;+         }+         // fallthrough+      case 0x1D: // callgsubr+         if (sp < 1) return STBTT__CSERR("call(g|)subr stack");+         v = (int) s[--sp];+         if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");+         subr_stack[subr_stack_height++] = b;+         b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);+         if (b.size == 0) return STBTT__CSERR("subr not found");+         b.cursor = 0;+         clear_stack = 0;+         break;++      case 0x0B: // return+         if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");+         b = subr_stack[--subr_stack_height];+         clear_stack = 0;+         break;++      case 0x0E: // endchar+         stbtt__csctx_close_shape(c);+         return 1;++      case 0x0C: { // two-byte escape+         float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;+         float dx, dy;+         int b1 = stbtt__buf_get8(&b);+         switch (b1) {+         // @TODO These "flex" implementations ignore the flex-depth and resolution,+         // and always draw beziers.+         case 0x22: // hflex+            if (sp < 7) return STBTT__CSERR("hflex stack");+            dx1 = s[0];+            dx2 = s[1];+            dy2 = s[2];+            dx3 = s[3];+            dx4 = s[4];+            dx5 = s[5];+            dx6 = s[6];+            stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);+            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);+            break;++         case 0x23: // flex+            if (sp < 13) return STBTT__CSERR("flex stack");+            dx1 = s[0];+            dy1 = s[1];+            dx2 = s[2];+            dy2 = s[3];+            dx3 = s[4];+            dy3 = s[5];+            dx4 = s[6];+            dy4 = s[7];+            dx5 = s[8];+            dy5 = s[9];+            dx6 = s[10];+            dy6 = s[11];+            //fd is s[12]+            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);+            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);+            break;++         case 0x24: // hflex1+            if (sp < 9) return STBTT__CSERR("hflex1 stack");+            dx1 = s[0];+            dy1 = s[1];+            dx2 = s[2];+            dy2 = s[3];+            dx3 = s[4];+            dx4 = s[5];+            dx5 = s[6];+            dy5 = s[7];+            dx6 = s[8];+            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);+            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));+            break;++         case 0x25: // flex1+            if (sp < 11) return STBTT__CSERR("flex1 stack");+            dx1 = s[0];+            dy1 = s[1];+            dx2 = s[2];+            dy2 = s[3];+            dx3 = s[4];+            dy3 = s[5];+            dx4 = s[6];+            dy4 = s[7];+            dx5 = s[8];+            dy5 = s[9];+            dx6 = dy6 = s[10];+            dx = dx1+dx2+dx3+dx4+dx5;+            dy = dy1+dy2+dy3+dy4+dy5;+            if (STBTT_fabs(dx) > STBTT_fabs(dy))+               dy6 = -dy;+            else+               dx6 = -dx;+            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);+            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);+            break;++         default:+            return STBTT__CSERR("unimplemented");+         }+      } break;++      default:+         if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))+            return STBTT__CSERR("reserved operator");++         // push immediate+         if (b0 == 255) {+            f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;+         } else {+            stbtt__buf_skip(&b, -1);+            f = (float)(stbtt_int16)stbtt__cff_int(&b);+         }+         if (sp >= 48) return STBTT__CSERR("push stack overflow");+         s[sp++] = f;+         clear_stack = 0;+         break;+      }+      if (clear_stack) sp = 0;+   }+   return STBTT__CSERR("no endchar");++#undef STBTT__CSERR+}++static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)+{+   // runs the charstring twice, once to count and once to output (to avoid realloc)+   stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);+   stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);+   if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {+      *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);+      output_ctx.pvertices = *pvertices;+      if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {+         STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);+         return output_ctx.num_vertices;+      }+   }+   *pvertices = NULL;+   return 0;+}++static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)+{+   stbtt__csctx c = STBTT__CSCTX_INIT(1);+   int r = stbtt__run_charstring(info, glyph_index, &c);+   if (x0)  *x0 = r ? c.min_x : 0;+   if (y0)  *y0 = r ? c.min_y : 0;+   if (x1)  *x1 = r ? c.max_x : 0;+   if (y1)  *y1 = r ? c.max_y : 0;+   return r ? c.num_vertices : 0;+}++STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)+{+   if (!info->cff.size)+      return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);+   else+      return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);+}++STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)+{+   stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);+   if (glyph_index < numOfLongHorMetrics) {+      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*glyph_index);+      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);+   } else {+      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));+      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));+   }+}++STBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info)+{+   stbtt_uint8 *data = info->data + info->kern;++   // we only look at the first table. it must be 'horizontal' and format 0.+   if (!info->kern)+      return 0;+   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1+      return 0;+   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format+      return 0;++   return ttUSHORT(data+10);+}++STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length)+{+   stbtt_uint8 *data = info->data + info->kern;+   int k, length;++   // we only look at the first table. it must be 'horizontal' and format 0.+   if (!info->kern)+      return 0;+   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1+      return 0;+   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format+      return 0;++   length = ttUSHORT(data+10);+   if (table_length < length)+      length = table_length;++   for (k = 0; k < length; k++)+   {+      table[k].glyph1 = ttUSHORT(data+18+(k*6));+      table[k].glyph2 = ttUSHORT(data+20+(k*6));+      table[k].advance = ttSHORT(data+22+(k*6));+   }++   return length;+}++static int  stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)+{+   stbtt_uint8 *data = info->data + info->kern;+   stbtt_uint32 needle, straw;+   int l, r, m;++   // we only look at the first table. it must be 'horizontal' and format 0.+   if (!info->kern)+      return 0;+   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1+      return 0;+   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format+      return 0;++   l = 0;+   r = ttUSHORT(data+10) - 1;+   needle = glyph1 << 16 | glyph2;+   while (l <= r) {+      m = (l + r) >> 1;+      straw = ttULONG(data+18+(m*6)); // note: unaligned read+      if (needle < straw)+         r = m - 1;+      else if (needle > straw)+         l = m + 1;+      else+         return ttSHORT(data+22+(m*6));+   }+   return 0;+}++static stbtt_int32  stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)+{+    stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);+    switch(coverageFormat) {+        case 1: {+            stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);++            // Binary search.+            stbtt_int32 l=0, r=glyphCount-1, m;+            int straw, needle=glyph;+            while (l <= r) {+                stbtt_uint8 *glyphArray = coverageTable + 4;+                stbtt_uint16 glyphID;+                m = (l + r) >> 1;+                glyphID = ttUSHORT(glyphArray + 2 * m);+                straw = glyphID;+                if (needle < straw)+                    r = m - 1;+                else if (needle > straw)+                    l = m + 1;+                else {+                     return m;+                }+            }+        } break;++        case 2: {+            stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);+            stbtt_uint8 *rangeArray = coverageTable + 4;++            // Binary search.+            stbtt_int32 l=0, r=rangeCount-1, m;+            int strawStart, strawEnd, needle=glyph;+            while (l <= r) {+                stbtt_uint8 *rangeRecord;+                m = (l + r) >> 1;+                rangeRecord = rangeArray + 6 * m;+                strawStart = ttUSHORT(rangeRecord);+                strawEnd = ttUSHORT(rangeRecord + 2);+                if (needle < strawStart)+                    r = m - 1;+                else if (needle > strawEnd)+                    l = m + 1;+                else {+                    stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);+                    return startCoverageIndex + glyph - strawStart;+                }+            }+        } break;++        default: {+            // There are no other cases.+            STBTT_assert(0);+        } break;+    }++    return -1;+}++static stbtt_int32  stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)+{+    stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);+    switch(classDefFormat)+    {+        case 1: {+            stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);+            stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);+            stbtt_uint8 *classDef1ValueArray = classDefTable + 6;++            if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)+                return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));++            classDefTable = classDef1ValueArray + 2 * glyphCount;+        } break;++        case 2: {+            stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);+            stbtt_uint8 *classRangeRecords = classDefTable + 4;++            // Binary search.+            stbtt_int32 l=0, r=classRangeCount-1, m;+            int strawStart, strawEnd, needle=glyph;+            while (l <= r) {+                stbtt_uint8 *classRangeRecord;+                m = (l + r) >> 1;+                classRangeRecord = classRangeRecords + 6 * m;+                strawStart = ttUSHORT(classRangeRecord);+                strawEnd = ttUSHORT(classRangeRecord + 2);+                if (needle < strawStart)+                    r = m - 1;+                else if (needle > strawEnd)+                    l = m + 1;+                else+                    return (stbtt_int32)ttUSHORT(classRangeRecord + 4);+            }++            classDefTable = classRangeRecords + 6 * classRangeCount;+        } break;++        default: {+            // There are no other cases.+            STBTT_assert(0);+        } break;+    }++    return -1;+}++// Define to STBTT_assert(x) if you want to break on unimplemented formats.+#define STBTT_GPOS_TODO_assert(x)++static stbtt_int32  stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)+{+    stbtt_uint16 lookupListOffset;+    stbtt_uint8 *lookupList;+    stbtt_uint16 lookupCount;+    stbtt_uint8 *data;+    stbtt_int32 i;++    if (!info->gpos) return 0;++    data = info->data + info->gpos;++    if (ttUSHORT(data+0) != 1) return 0; // Major version 1+    if (ttUSHORT(data+2) != 0) return 0; // Minor version 0++    lookupListOffset = ttUSHORT(data+8);+    lookupList = data + lookupListOffset;+    lookupCount = ttUSHORT(lookupList);++    for (i=0; i<lookupCount; ++i) {+        stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);+        stbtt_uint8 *lookupTable = lookupList + lookupOffset;++        stbtt_uint16 lookupType = ttUSHORT(lookupTable);+        stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);+        stbtt_uint8 *subTableOffsets = lookupTable + 6;+        switch(lookupType) {+            case 2: { // Pair Adjustment Positioning Subtable+                stbtt_int32 sti;+                for (sti=0; sti<subTableCount; sti++) {+                    stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);+                    stbtt_uint8 *table = lookupTable + subtableOffset;+                    stbtt_uint16 posFormat = ttUSHORT(table);+                    stbtt_uint16 coverageOffset = ttUSHORT(table + 2);+                    stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);+                    if (coverageIndex == -1) continue;++                    switch (posFormat) {+                        case 1: {+                            stbtt_int32 l, r, m;+                            int straw, needle;+                            stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);+                            stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);+                            stbtt_int32 valueRecordPairSizeInBytes = 2;+                            stbtt_uint16 pairSetCount = ttUSHORT(table + 8);+                            stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);+                            stbtt_uint8 *pairValueTable = table + pairPosOffset;+                            stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);+                            stbtt_uint8 *pairValueArray = pairValueTable + 2;+                            // TODO: Support more formats.+                            STBTT_GPOS_TODO_assert(valueFormat1 == 4);+                            if (valueFormat1 != 4) return 0;+                            STBTT_GPOS_TODO_assert(valueFormat2 == 0);+                            if (valueFormat2 != 0) return 0;++                            STBTT_assert(coverageIndex < pairSetCount);+                            STBTT__NOTUSED(pairSetCount);++                            needle=glyph2;+                            r=pairValueCount-1;+                            l=0;++                            // Binary search.+                            while (l <= r) {+                                stbtt_uint16 secondGlyph;+                                stbtt_uint8 *pairValue;+                                m = (l + r) >> 1;+                                pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;+                                secondGlyph = ttUSHORT(pairValue);+                                straw = secondGlyph;+                                if (needle < straw)+                                    r = m - 1;+                                else if (needle > straw)+                                    l = m + 1;+                                else {+                                    stbtt_int16 xAdvance = ttSHORT(pairValue + 2);+                                    return xAdvance;+                                }+                            }+                        } break;++                        case 2: {+                            stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);+                            stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);++                            stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);+                            stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);+                            int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);+                            int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);++                            stbtt_uint16 class1Count = ttUSHORT(table + 12);+                            stbtt_uint16 class2Count = ttUSHORT(table + 14);+                            STBTT_assert(glyph1class < class1Count);+                            STBTT_assert(glyph2class < class2Count);++                            // TODO: Support more formats.+                            STBTT_GPOS_TODO_assert(valueFormat1 == 4);+                            if (valueFormat1 != 4) return 0;+                            STBTT_GPOS_TODO_assert(valueFormat2 == 0);+                            if (valueFormat2 != 0) return 0;++                            if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {+                                stbtt_uint8 *class1Records = table + 16;+                                stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);+                                stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);+                                return xAdvance;+                            }+                        } break;++                        default: {+                            // There are no other cases.+                            STBTT_assert(0);+                            break;+                        };+                    }+                }+                break;+            };++            default:+                // TODO: Implement other stuff.+                break;+        }+    }++    return 0;+}++STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)+{+   int xAdvance = 0;++   if (info->gpos)+      xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);+   else if (info->kern)+      xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);++   return xAdvance;+}++STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)+{+   if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs+      return 0;+   return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));+}++STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)+{+   stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);+}++STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)+{+   if (ascent ) *ascent  = ttSHORT(info->data+info->hhea + 4);+   if (descent) *descent = ttSHORT(info->data+info->hhea + 6);+   if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);+}++STBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)+{+   int tab = stbtt__find_table(info->data, info->fontstart, "OS/2");+   if (!tab)+      return 0;+   if (typoAscent ) *typoAscent  = ttSHORT(info->data+tab + 68);+   if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);+   if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);+   return 1;+}++STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)+{+   *x0 = ttSHORT(info->data + info->head + 36);+   *y0 = ttSHORT(info->data + info->head + 38);+   *x1 = ttSHORT(info->data + info->head + 40);+   *y1 = ttSHORT(info->data + info->head + 42);+}++STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)+{+   int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);+   return (float) height / fheight;+}++STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)+{+   int unitsPerEm = ttUSHORT(info->data + info->head + 18);+   return pixels / unitsPerEm;+}++STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)+{+   STBTT_free(v, info->userdata);+}++STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl)+{+   int i;+   stbtt_uint8 *data = info->data;+   stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info);++   int numEntries = ttUSHORT(svg_doc_list);+   stbtt_uint8 *svg_docs = svg_doc_list + 2;++   for(i=0; i<numEntries; i++) {+      stbtt_uint8 *svg_doc = svg_docs + (12 * i);+      if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))+         return svg_doc;+   }+   return 0;+}++STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg)+{+   stbtt_uint8 *data = info->data;+   stbtt_uint8 *svg_doc;++   if (info->svg == 0)+      return 0;++   svg_doc = stbtt_FindSVGDoc(info, gl);+   if (svg_doc != NULL) {+      *svg = (char *) data + info->svg + ttULONG(svg_doc + 4);+      return ttULONG(svg_doc + 8);+   } else {+      return 0;+   }+}++STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg)+{+   return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);+}++//////////////////////////////////////////////////////////////////////////////+//+// antialiasing software rasterizer+//++STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)+{+   int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning+   if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {+      // e.g. space character+      if (ix0) *ix0 = 0;+      if (iy0) *iy0 = 0;+      if (ix1) *ix1 = 0;+      if (iy1) *iy1 = 0;+   } else {+      // move to integral bboxes (treating pixels as little squares, what pixels get touched)?+      if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);+      if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);+      if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);+      if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);+   }+}++STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)+{+   stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);+}++STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)+{+   stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);+}++STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)+{+   stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);+}++//////////////////////////////////////////////////////////////////////////////+//+//  Rasterizer++typedef struct stbtt__hheap_chunk+{+   struct stbtt__hheap_chunk *next;+} stbtt__hheap_chunk;++typedef struct stbtt__hheap+{+   struct stbtt__hheap_chunk *head;+   void   *first_free;+   int    num_remaining_in_head_chunk;+} stbtt__hheap;++static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)+{+   if (hh->first_free) {+      void *p = hh->first_free;+      hh->first_free = * (void **) p;+      return p;+   } else {+      if (hh->num_remaining_in_head_chunk == 0) {+         int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);+         stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);+         if (c == NULL)+            return NULL;+         c->next = hh->head;+         hh->head = c;+         hh->num_remaining_in_head_chunk = count;+      }+      --hh->num_remaining_in_head_chunk;+      return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;+   }+}++static void stbtt__hheap_free(stbtt__hheap *hh, void *p)+{+   *(void **) p = hh->first_free;+   hh->first_free = p;+}++static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)+{+   stbtt__hheap_chunk *c = hh->head;+   while (c) {+      stbtt__hheap_chunk *n = c->next;+      STBTT_free(c, userdata);+      c = n;+   }+}++typedef struct stbtt__edge {+   float x0,y0, x1,y1;+   int invert;+} stbtt__edge;+++typedef struct stbtt__active_edge+{+   struct stbtt__active_edge *next;+   #if STBTT_RASTERIZER_VERSION==1+   int x,dx;+   float ey;+   int direction;+   #elif STBTT_RASTERIZER_VERSION==2+   float fx,fdx,fdy;+   float direction;+   float sy;+   float ey;+   #else+   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"+   #endif+} stbtt__active_edge;++#if STBTT_RASTERIZER_VERSION == 1+#define STBTT_FIXSHIFT   10+#define STBTT_FIX        (1 << STBTT_FIXSHIFT)+#define STBTT_FIXMASK    (STBTT_FIX-1)++static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)+{+   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);+   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);+   STBTT_assert(z != NULL);+   if (!z) return z;++   // round dx down to avoid overshooting+   if (dxdy < 0)+      z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);+   else+      z->dx = STBTT_ifloor(STBTT_FIX * dxdy);++   z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount+   z->x -= off_x * STBTT_FIX;++   z->ey = e->y1;+   z->next = 0;+   z->direction = e->invert ? 1 : -1;+   return z;+}+#elif STBTT_RASTERIZER_VERSION == 2+static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)+{+   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);+   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);+   STBTT_assert(z != NULL);+   //STBTT_assert(e->y0 <= start_point);+   if (!z) return z;+   z->fdx = dxdy;+   z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;+   z->fx = e->x0 + dxdy * (start_point - e->y0);+   z->fx -= off_x;+   z->direction = e->invert ? 1.0f : -1.0f;+   z->sy = e->y0;+   z->ey = e->y1;+   z->next = 0;+   return z;+}+#else+#error "Unrecognized value of STBTT_RASTERIZER_VERSION"+#endif++#if STBTT_RASTERIZER_VERSION == 1+// note: this routine clips fills that extend off the edges... ideally this+// wouldn't happen, but it could happen if the truetype glyph bounding boxes+// are wrong, or if the user supplies a too-small bitmap+static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)+{+   // non-zero winding fill+   int x0=0, w=0;++   while (e) {+      if (w == 0) {+         // if we're currently at zero, we need to record the edge start point+         x0 = e->x; w += e->direction;+      } else {+         int x1 = e->x; w += e->direction;+         // if we went to zero, we need to draw+         if (w == 0) {+            int i = x0 >> STBTT_FIXSHIFT;+            int j = x1 >> STBTT_FIXSHIFT;++            if (i < len && j >= 0) {+               if (i == j) {+                  // x0,x1 are the same pixel, so compute combined coverage+                  scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);+               } else {+                  if (i >= 0) // add antialiasing for x0+                     scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);+                  else+                     i = -1; // clip++                  if (j < len) // add antialiasing for x1+                     scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);+                  else+                     j = len; // clip++                  for (++i; i < j; ++i) // fill pixels between x0 and x1+                     scanline[i] = scanline[i] + (stbtt_uint8) max_weight;+               }+            }+         }+      }++      e = e->next;+   }+}++static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)+{+   stbtt__hheap hh = { 0, 0, 0 };+   stbtt__active_edge *active = NULL;+   int y,j=0;+   int max_weight = (255 / vsubsample);  // weight per vertical scanline+   int s; // vertical subsample index+   unsigned char scanline_data[512], *scanline;++   if (result->w > 512)+      scanline = (unsigned char *) STBTT_malloc(result->w, userdata);+   else+      scanline = scanline_data;++   y = off_y * vsubsample;+   e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;++   while (j < result->h) {+      STBTT_memset(scanline, 0, result->w);+      for (s=0; s < vsubsample; ++s) {+         // find center of pixel for this scanline+         float scan_y = y + 0.5f;+         stbtt__active_edge **step = &active;++         // update all active edges;+         // remove all active edges that terminate before the center of this scanline+         while (*step) {+            stbtt__active_edge * z = *step;+            if (z->ey <= scan_y) {+               *step = z->next; // delete from list+               STBTT_assert(z->direction);+               z->direction = 0;+               stbtt__hheap_free(&hh, z);+            } else {+               z->x += z->dx; // advance to position for current scanline+               step = &((*step)->next); // advance through list+            }+         }++         // resort the list if needed+         for(;;) {+            int changed=0;+            step = &active;+            while (*step && (*step)->next) {+               if ((*step)->x > (*step)->next->x) {+                  stbtt__active_edge *t = *step;+                  stbtt__active_edge *q = t->next;++                  t->next = q->next;+                  q->next = t;+                  *step = q;+                  changed = 1;+               }+               step = &(*step)->next;+            }+            if (!changed) break;+         }++         // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline+         while (e->y0 <= scan_y) {+            if (e->y1 > scan_y) {+               stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);+               if (z != NULL) {+                  // find insertion point+                  if (active == NULL)+                     active = z;+                  else if (z->x < active->x) {+                     // insert at front+                     z->next = active;+                     active = z;+                  } else {+                     // find thing to insert AFTER+                     stbtt__active_edge *p = active;+                     while (p->next && p->next->x < z->x)+                        p = p->next;+                     // at this point, p->next->x is NOT < z->x+                     z->next = p->next;+                     p->next = z;+                  }+               }+            }+            ++e;+         }++         // now process all active edges in XOR fashion+         if (active)+            stbtt__fill_active_edges(scanline, result->w, active, max_weight);++         ++y;+      }+      STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);+      ++j;+   }++   stbtt__hheap_cleanup(&hh, userdata);++   if (scanline != scanline_data)+      STBTT_free(scanline, userdata);+}++#elif STBTT_RASTERIZER_VERSION == 2++// the edge passed in here does not cross the vertical line at x or the vertical line at x+1+// (i.e. it has already been clipped to those)+static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)+{+   if (y0 == y1) return;+   STBTT_assert(y0 < y1);+   STBTT_assert(e->sy <= e->ey);+   if (y0 > e->ey) return;+   if (y1 < e->sy) return;+   if (y0 < e->sy) {+      x0 += (x1-x0) * (e->sy - y0) / (y1-y0);+      y0 = e->sy;+   }+   if (y1 > e->ey) {+      x1 += (x1-x0) * (e->ey - y1) / (y1-y0);+      y1 = e->ey;+   }++   if (x0 == x)+      STBTT_assert(x1 <= x+1);+   else if (x0 == x+1)+      STBTT_assert(x1 >= x);+   else if (x0 <= x)+      STBTT_assert(x1 <= x);+   else if (x0 >= x+1)+      STBTT_assert(x1 >= x+1);+   else+      STBTT_assert(x1 >= x && x1 <= x+1);++   if (x0 <= x && x1 <= x)+      scanline[x] += e->direction * (y1-y0);+   else if (x0 >= x+1 && x1 >= x+1)+      ;+   else {+      STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);+      scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position+   }+}++static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)+{+   float y_bottom = y_top+1;++   while (e) {+      // brute force every pixel++      // compute intersection points with top & bottom+      STBTT_assert(e->ey >= y_top);++      if (e->fdx == 0) {+         float x0 = e->fx;+         if (x0 < len) {+            if (x0 >= 0) {+               stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);+               stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);+            } else {+               stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);+            }+         }+      } else {+         float x0 = e->fx;+         float dx = e->fdx;+         float xb = x0 + dx;+         float x_top, x_bottom;+         float sy0,sy1;+         float dy = e->fdy;+         STBTT_assert(e->sy <= y_bottom && e->ey >= y_top);++         // compute endpoints of line segment clipped to this scanline (if the+         // line segment starts on this scanline. x0 is the intersection of the+         // line with y_top, but that may be off the line segment.+         if (e->sy > y_top) {+            x_top = x0 + dx * (e->sy - y_top);+            sy0 = e->sy;+         } else {+            x_top = x0;+            sy0 = y_top;+         }+         if (e->ey < y_bottom) {+            x_bottom = x0 + dx * (e->ey - y_top);+            sy1 = e->ey;+         } else {+            x_bottom = xb;+            sy1 = y_bottom;+         }++         if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {+            // from here on, we don't have to range check x values++            if ((int) x_top == (int) x_bottom) {+               float height;+               // simple case, only spans one pixel+               int x = (int) x_top;+               height = sy1 - sy0;+               STBTT_assert(x >= 0 && x < len);+               scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2)  * height;+               scanline_fill[x] += e->direction * height; // everything right of this pixel is filled+            } else {+               int x,x1,x2;+               float y_crossing, step, sign, area;+               // covers 2+ pixels+               if (x_top > x_bottom) {+                  // flip scanline vertically; signed area is the same+                  float t;+                  sy0 = y_bottom - (sy0 - y_top);+                  sy1 = y_bottom - (sy1 - y_top);+                  t = sy0, sy0 = sy1, sy1 = t;+                  t = x_bottom, x_bottom = x_top, x_top = t;+                  dx = -dx;+                  dy = -dy;+                  t = x0, x0 = xb, xb = t;+               }++               x1 = (int) x_top;+               x2 = (int) x_bottom;+               // compute intersection with y axis at x1+1+               y_crossing = (x1+1 - x0) * dy + y_top;++               sign = e->direction;+               // area of the rectangle covered from y0..y_crossing+               area = sign * (y_crossing-sy0);+               // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)+               scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);++               step = sign * dy;+               for (x = x1+1; x < x2; ++x) {+                  scanline[x] += area + step/2;+                  area += step;+               }+               y_crossing += dy * (x2 - (x1+1));++               STBTT_assert(STBTT_fabs(area) <= 1.01f);++               scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);++               scanline_fill[x2] += sign * (sy1-sy0);+            }+         } else {+            // if edge goes outside of box we're drawing, we require+            // clipping logic. since this does not match the intended use+            // of this library, we use a different, very slow brute+            // force implementation+            int x;+            for (x=0; x < len; ++x) {+               // cases:+               //+               // there can be up to two intersections with the pixel. any intersection+               // with left or right edges can be handled by splitting into two (or three)+               // regions. intersections with top & bottom do not necessitate case-wise logic.+               //+               // the old way of doing this found the intersections with the left & right edges,+               // then used some simple logic to produce up to three segments in sorted order+               // from top-to-bottom. however, this had a problem: if an x edge was epsilon+               // across the x border, then the corresponding y position might not be distinct+               // from the other y segment, and it might ignored as an empty segment. to avoid+               // that, we need to explicitly produce segments based on x positions.++               // rename variables to clearly-defined pairs+               float y0 = y_top;+               float x1 = (float) (x);+               float x2 = (float) (x+1);+               float x3 = xb;+               float y3 = y_bottom;++               // x = e->x + e->dx * (y-y_top)+               // (y-y_top) = (x - e->x) / e->dx+               // y = (x - e->x) / e->dx + y_top+               float y1 = (x - x0) / dx + y_top;+               float y2 = (x+1 - x0) / dx + y_top;++               if (x0 < x1 && x3 > x2) {         // three segments descending down-right+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);+               } else if (x3 < x1 && x0 > x2) {  // three segments descending down-left+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);+               } else if (x0 < x1 && x3 > x1) {  // two segments across x, down-right+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);+               } else if (x3 < x1 && x0 > x1) {  // two segments across x, down-left+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);+               } else if (x0 < x2 && x3 > x2) {  // two segments across x+1, down-right+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);+               } else if (x3 < x2 && x0 > x2) {  // two segments across x+1, down-left+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);+               } else {  // one segment+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);+               }+            }+         }+      }+      e = e->next;+   }+}++// directly AA rasterize edges w/o supersampling+static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)+{+   stbtt__hheap hh = { 0, 0, 0 };+   stbtt__active_edge *active = NULL;+   int y,j=0, i;+   float scanline_data[129], *scanline, *scanline2;++   STBTT__NOTUSED(vsubsample);++   if (result->w > 64)+      scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);+   else+      scanline = scanline_data;++   scanline2 = scanline + result->w;++   y = off_y;+   e[n].y0 = (float) (off_y + result->h) + 1;++   while (j < result->h) {+      // find center of pixel for this scanline+      float scan_y_top    = y + 0.0f;+      float scan_y_bottom = y + 1.0f;+      stbtt__active_edge **step = &active;++      STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));+      STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));++      // update all active edges;+      // remove all active edges that terminate before the top of this scanline+      while (*step) {+         stbtt__active_edge * z = *step;+         if (z->ey <= scan_y_top) {+            *step = z->next; // delete from list+            STBTT_assert(z->direction);+            z->direction = 0;+            stbtt__hheap_free(&hh, z);+         } else {+            step = &((*step)->next); // advance through list+         }+      }++      // insert all edges that start before the bottom of this scanline+      while (e->y0 <= scan_y_bottom) {+         if (e->y0 != e->y1) {+            stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);+            if (z != NULL) {+               if (j == 0 && off_y != 0) {+                  if (z->ey < scan_y_top) {+                     // this can happen due to subpixel positioning and some kind of fp rounding error i think+                     z->ey = scan_y_top;+                  }+               }+               STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds+               // insert at front+               z->next = active;+               active = z;+            }+         }+         ++e;+      }++      // now process all active edges+      if (active)+         stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);++      {+         float sum = 0;+         for (i=0; i < result->w; ++i) {+            float k;+            int m;+            sum += scanline2[i];+            k = scanline[i] + sum;+            k = (float) STBTT_fabs(k)*255 + 0.5f;+            m = (int) k;+            if (m > 255) m = 255;+            result->pixels[j*result->stride + i] = (unsigned char) m;+         }+      }+      // advance all the edges+      step = &active;+      while (*step) {+         stbtt__active_edge *z = *step;+         z->fx += z->fdx; // advance to position for current scanline+         step = &((*step)->next); // advance through list+      }++      ++y;+      ++j;+   }++   stbtt__hheap_cleanup(&hh, userdata);++   if (scanline != scanline_data)+      STBTT_free(scanline, userdata);+}+#else+#error "Unrecognized value of STBTT_RASTERIZER_VERSION"+#endif++#define STBTT__COMPARE(a,b)  ((a)->y0 < (b)->y0)++static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)+{+   int i,j;+   for (i=1; i < n; ++i) {+      stbtt__edge t = p[i], *a = &t;+      j = i;+      while (j > 0) {+         stbtt__edge *b = &p[j-1];+         int c = STBTT__COMPARE(a,b);+         if (!c) break;+         p[j] = p[j-1];+         --j;+      }+      if (i != j)+         p[j] = t;+   }+}++static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)+{+   /* threshold for transitioning to insertion sort */+   while (n > 12) {+      stbtt__edge t;+      int c01,c12,c,m,i,j;++      /* compute median of three */+      m = n >> 1;+      c01 = STBTT__COMPARE(&p[0],&p[m]);+      c12 = STBTT__COMPARE(&p[m],&p[n-1]);+      /* if 0 >= mid >= end, or 0 < mid < end, then use mid */+      if (c01 != c12) {+         /* otherwise, we'll need to swap something else to middle */+         int z;+         c = STBTT__COMPARE(&p[0],&p[n-1]);+         /* 0>mid && mid<n:  0>n => n; 0<n => 0 */+         /* 0<mid && mid>n:  0>n => 0; 0<n => n */+         z = (c == c12) ? 0 : n-1;+         t = p[z];+         p[z] = p[m];+         p[m] = t;+      }+      /* now p[m] is the median-of-three */+      /* swap it to the beginning so it won't move around */+      t = p[0];+      p[0] = p[m];+      p[m] = t;++      /* partition loop */+      i=1;+      j=n-1;+      for(;;) {+         /* handling of equality is crucial here */+         /* for sentinels & efficiency with duplicates */+         for (;;++i) {+            if (!STBTT__COMPARE(&p[i], &p[0])) break;+         }+         for (;;--j) {+            if (!STBTT__COMPARE(&p[0], &p[j])) break;+         }+         /* make sure we haven't crossed */+         if (i >= j) break;+         t = p[i];+         p[i] = p[j];+         p[j] = t;++         ++i;+         --j;+      }+      /* recurse on smaller side, iterate on larger */+      if (j < (n-i)) {+         stbtt__sort_edges_quicksort(p,j);+         p = p+i;+         n = n-i;+      } else {+         stbtt__sort_edges_quicksort(p+i, n-i);+         n = j;+      }+   }+}++static void stbtt__sort_edges(stbtt__edge *p, int n)+{+   stbtt__sort_edges_quicksort(p, n);+   stbtt__sort_edges_ins_sort(p, n);+}++typedef struct+{+   float x,y;+} stbtt__point;++static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)+{+   float y_scale_inv = invert ? -scale_y : scale_y;+   stbtt__edge *e;+   int n,i,j,k,m;+#if STBTT_RASTERIZER_VERSION == 1+   int vsubsample = result->h < 8 ? 15 : 5;+#elif STBTT_RASTERIZER_VERSION == 2+   int vsubsample = 1;+#else+   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"+#endif+   // vsubsample should divide 255 evenly; otherwise we won't reach full opacity++   // now we have to blow out the windings into explicit edge lists+   n = 0;+   for (i=0; i < windings; ++i)+      n += wcount[i];++   e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel+   if (e == 0) return;+   n = 0;++   m=0;+   for (i=0; i < windings; ++i) {+      stbtt__point *p = pts + m;+      m += wcount[i];+      j = wcount[i]-1;+      for (k=0; k < wcount[i]; j=k++) {+         int a=k,b=j;+         // skip the edge if horizontal+         if (p[j].y == p[k].y)+            continue;+         // add edge from j to k to the list+         e[n].invert = 0;+         if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {+            e[n].invert = 1;+            a=j,b=k;+         }+         e[n].x0 = p[a].x * scale_x + shift_x;+         e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;+         e[n].x1 = p[b].x * scale_x + shift_x;+         e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;+         ++n;+      }+   }++   // now sort the edges by their highest point (should snap to integer, and then by x)+   //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);+   stbtt__sort_edges(e, n);++   // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule+   stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);++   STBTT_free(e, userdata);+}++static void stbtt__add_point(stbtt__point *points, int n, float x, float y)+{+   if (!points) return; // during first pass, it's unallocated+   points[n].x = x;+   points[n].y = y;+}++// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching+static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)+{+   // midpoint+   float mx = (x0 + 2*x1 + x2)/4;+   float my = (y0 + 2*y1 + y2)/4;+   // versus directly drawn line+   float dx = (x0+x2)/2 - mx;+   float dy = (y0+y2)/2 - my;+   if (n > 16) // 65536 segments on one curve better be enough!+      return 1;+   if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA+      stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);+      stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);+   } else {+      stbtt__add_point(points, *num_points,x2,y2);+      *num_points = *num_points+1;+   }+   return 1;+}++static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n)+{+   // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough+   float dx0 = x1-x0;+   float dy0 = y1-y0;+   float dx1 = x2-x1;+   float dy1 = y2-y1;+   float dx2 = x3-x2;+   float dy2 = y3-y2;+   float dx = x3-x0;+   float dy = y3-y0;+   float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));+   float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);+   float flatness_squared = longlen*longlen-shortlen*shortlen;++   if (n > 16) // 65536 segments on one curve better be enough!+      return;++   if (flatness_squared > objspace_flatness_squared) {+      float x01 = (x0+x1)/2;+      float y01 = (y0+y1)/2;+      float x12 = (x1+x2)/2;+      float y12 = (y1+y2)/2;+      float x23 = (x2+x3)/2;+      float y23 = (y2+y3)/2;++      float xa = (x01+x12)/2;+      float ya = (y01+y12)/2;+      float xb = (x12+x23)/2;+      float yb = (y12+y23)/2;++      float mx = (xa+xb)/2;+      float my = (ya+yb)/2;++      stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);+      stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);+   } else {+      stbtt__add_point(points, *num_points,x3,y3);+      *num_points = *num_points+1;+   }+}++// returns number of contours+static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)+{+   stbtt__point *points=0;+   int num_points=0;++   float objspace_flatness_squared = objspace_flatness * objspace_flatness;+   int i,n=0,start=0, pass;++   // count how many "moves" there are to get the contour count+   for (i=0; i < num_verts; ++i)+      if (vertices[i].type == STBTT_vmove)+         ++n;++   *num_contours = n;+   if (n == 0) return 0;++   *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);++   if (*contour_lengths == 0) {+      *num_contours = 0;+      return 0;+   }++   // make two passes through the points so we don't need to realloc+   for (pass=0; pass < 2; ++pass) {+      float x=0,y=0;+      if (pass == 1) {+         points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);+         if (points == NULL) goto error;+      }+      num_points = 0;+      n= -1;+      for (i=0; i < num_verts; ++i) {+         switch (vertices[i].type) {+            case STBTT_vmove:+               // start the next contour+               if (n >= 0)+                  (*contour_lengths)[n] = num_points - start;+               ++n;+               start = num_points;++               x = vertices[i].x, y = vertices[i].y;+               stbtt__add_point(points, num_points++, x,y);+               break;+            case STBTT_vline:+               x = vertices[i].x, y = vertices[i].y;+               stbtt__add_point(points, num_points++, x, y);+               break;+            case STBTT_vcurve:+               stbtt__tesselate_curve(points, &num_points, x,y,+                                        vertices[i].cx, vertices[i].cy,+                                        vertices[i].x,  vertices[i].y,+                                        objspace_flatness_squared, 0);+               x = vertices[i].x, y = vertices[i].y;+               break;+            case STBTT_vcubic:+               stbtt__tesselate_cubic(points, &num_points, x,y,+                                        vertices[i].cx, vertices[i].cy,+                                        vertices[i].cx1, vertices[i].cy1,+                                        vertices[i].x,  vertices[i].y,+                                        objspace_flatness_squared, 0);+               x = vertices[i].x, y = vertices[i].y;+               break;+         }+      }+      (*contour_lengths)[n] = num_points - start;+   }++   return points;+error:+   STBTT_free(points, userdata);+   STBTT_free(*contour_lengths, userdata);+   *contour_lengths = 0;+   *num_contours = 0;+   return NULL;+}++STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)+{+   float scale            = scale_x > scale_y ? scale_y : scale_x;+   int winding_count      = 0;+   int *winding_lengths   = NULL;+   stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);+   if (windings) {+      stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);+      STBTT_free(winding_lengths, userdata);+      STBTT_free(windings, userdata);+   }+}++STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)+{+   STBTT_free(bitmap, userdata);+}++STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)+{+   int ix0,iy0,ix1,iy1;+   stbtt__bitmap gbm;+   stbtt_vertex *vertices;+   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);++   if (scale_x == 0) scale_x = scale_y;+   if (scale_y == 0) {+      if (scale_x == 0) {+         STBTT_free(vertices, info->userdata);+         return NULL;+      }+      scale_y = scale_x;+   }++   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);++   // now we get the size+   gbm.w = (ix1 - ix0);+   gbm.h = (iy1 - iy0);+   gbm.pixels = NULL; // in case we error++   if (width ) *width  = gbm.w;+   if (height) *height = gbm.h;+   if (xoff  ) *xoff   = ix0;+   if (yoff  ) *yoff   = iy0;++   if (gbm.w && gbm.h) {+      gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);+      if (gbm.pixels) {+         gbm.stride = gbm.w;++         stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);+      }+   }+   STBTT_free(vertices, info->userdata);+   return gbm.pixels;+}++STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)+{+   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);+}++STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)+{+   int ix0,iy0;+   stbtt_vertex *vertices;+   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);+   stbtt__bitmap gbm;++   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);+   gbm.pixels = output;+   gbm.w = out_w;+   gbm.h = out_h;+   gbm.stride = out_stride;++   if (gbm.w && gbm.h)+      stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);++   STBTT_free(vertices, info->userdata);+}++STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)+{+   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);+}++STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)+{+   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);+}++STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)+{+   stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));+}++STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)+{+   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));+}++STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)+{+   return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);+}++STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)+{+   stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);+}++//////////////////////////////////////////////////////////////////////////////+//+// bitmap baking+//+// This is SUPER-CRAPPY packing to keep source code small++static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)+                                float pixel_height,                     // height of font in pixels+                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in+                                int first_char, int num_chars,          // characters to bake+                                stbtt_bakedchar *chardata)+{+   float scale;+   int x,y,bottom_y, i;+   stbtt_fontinfo f;+   f.userdata = NULL;+   if (!stbtt_InitFont(&f, data, offset))+      return -1;+   STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels+   x=y=1;+   bottom_y = 1;++   scale = stbtt_ScaleForPixelHeight(&f, pixel_height);++   for (i=0; i < num_chars; ++i) {+      int advance, lsb, x0,y0,x1,y1,gw,gh;+      int g = stbtt_FindGlyphIndex(&f, first_char + i);+      stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);+      stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);+      gw = x1-x0;+      gh = y1-y0;+      if (x + gw + 1 >= pw)+         y = bottom_y, x = 1; // advance to next row+      if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row+         return -i;+      STBTT_assert(x+gw < pw);+      STBTT_assert(y+gh < ph);+      stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);+      chardata[i].x0 = (stbtt_int16) x;+      chardata[i].y0 = (stbtt_int16) y;+      chardata[i].x1 = (stbtt_int16) (x + gw);+      chardata[i].y1 = (stbtt_int16) (y + gh);+      chardata[i].xadvance = scale * advance;+      chardata[i].xoff     = (float) x0;+      chardata[i].yoff     = (float) y0;+      x = x + gw + 1;+      if (y+gh+1 > bottom_y)+         bottom_y = y+gh+1;+   }+   return bottom_y;+}++STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)+{+   float d3d_bias = opengl_fillrule ? 0 : -0.5f;+   float ipw = 1.0f / pw, iph = 1.0f / ph;+   const stbtt_bakedchar *b = chardata + char_index;+   int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);+   int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);++   q->x0 = round_x + d3d_bias;+   q->y0 = round_y + d3d_bias;+   q->x1 = round_x + b->x1 - b->x0 + d3d_bias;+   q->y1 = round_y + b->y1 - b->y0 + d3d_bias;++   q->s0 = b->x0 * ipw;+   q->t0 = b->y0 * iph;+   q->s1 = b->x1 * ipw;+   q->t1 = b->y1 * iph;++   *xpos += b->xadvance;+}++//////////////////////////////////////////////////////////////////////////////+//+// rectangle packing replacement routines if you don't have stb_rect_pack.h+//++#ifndef STB_RECT_PACK_VERSION++typedef int stbrp_coord;++////////////////////////////////////////////////////////////////////////////////////+//                                                                                //+//                                                                                //+// COMPILER WARNING ?!?!?                                                         //+//                                                                                //+//                                                                                //+// if you get a compile warning due to these symbols being defined more than      //+// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h"         //+//                                                                                //+////////////////////////////////////////////////////////////////////////////////////++typedef struct+{+   int width,height;+   int x,y,bottom_y;+} stbrp_context;++typedef struct+{+   unsigned char x;+} stbrp_node;++struct stbrp_rect+{+   stbrp_coord x,y;+   int id,w,h,was_packed;+};++static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)+{+   con->width  = pw;+   con->height = ph;+   con->x = 0;+   con->y = 0;+   con->bottom_y = 0;+   STBTT__NOTUSED(nodes);+   STBTT__NOTUSED(num_nodes);+}++static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)+{+   int i;+   for (i=0; i < num_rects; ++i) {+      if (con->x + rects[i].w > con->width) {+         con->x = 0;+         con->y = con->bottom_y;+      }+      if (con->y + rects[i].h > con->height)+         break;+      rects[i].x = con->x;+      rects[i].y = con->y;+      rects[i].was_packed = 1;+      con->x += rects[i].w;+      if (con->y + rects[i].h > con->bottom_y)+         con->bottom_y = con->y + rects[i].h;+   }+   for (   ; i < num_rects; ++i)+      rects[i].was_packed = 0;+}+#endif++//////////////////////////////////////////////////////////////////////////////+//+// bitmap baking+//+// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If+// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy.++STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)+{+   stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context)            ,alloc_context);+   int            num_nodes = pw - padding;+   stbrp_node    *nodes   = (stbrp_node    *) STBTT_malloc(sizeof(*nodes  ) * num_nodes,alloc_context);++   if (context == NULL || nodes == NULL) {+      if (context != NULL) STBTT_free(context, alloc_context);+      if (nodes   != NULL) STBTT_free(nodes  , alloc_context);+      return 0;+   }++   spc->user_allocator_context = alloc_context;+   spc->width = pw;+   spc->height = ph;+   spc->pixels = pixels;+   spc->pack_info = context;+   spc->nodes = nodes;+   spc->padding = padding;+   spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;+   spc->h_oversample = 1;+   spc->v_oversample = 1;+   spc->skip_missing = 0;++   stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);++   if (pixels)+      STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels++   return 1;+}++STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc)+{+   STBTT_free(spc->nodes    , spc->user_allocator_context);+   STBTT_free(spc->pack_info, spc->user_allocator_context);+}++STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample)+{+   STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE);+   STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE);+   if (h_oversample <= STBTT_MAX_OVERSAMPLE)+      spc->h_oversample = h_oversample;+   if (v_oversample <= STBTT_MAX_OVERSAMPLE)+      spc->v_oversample = v_oversample;+}++STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)+{+   spc->skip_missing = skip;+}++#define STBTT__OVER_MASK  (STBTT_MAX_OVERSAMPLE-1)++static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)+{+   unsigned char buffer[STBTT_MAX_OVERSAMPLE];+   int safe_w = w - kernel_width;+   int j;+   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze+   for (j=0; j < h; ++j) {+      int i;+      unsigned int total;+      STBTT_memset(buffer, 0, kernel_width);++      total = 0;++      // make kernel_width a constant in common cases so compiler can optimize out the divide+      switch (kernel_width) {+         case 2:+            for (i=0; i <= safe_w; ++i) {+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];+               pixels[i] = (unsigned char) (total / 2);+            }+            break;+         case 3:+            for (i=0; i <= safe_w; ++i) {+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];+               pixels[i] = (unsigned char) (total / 3);+            }+            break;+         case 4:+            for (i=0; i <= safe_w; ++i) {+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];+               pixels[i] = (unsigned char) (total / 4);+            }+            break;+         case 5:+            for (i=0; i <= safe_w; ++i) {+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];+               pixels[i] = (unsigned char) (total / 5);+            }+            break;+         default:+            for (i=0; i <= safe_w; ++i) {+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];+               pixels[i] = (unsigned char) (total / kernel_width);+            }+            break;+      }++      for (; i < w; ++i) {+         STBTT_assert(pixels[i] == 0);+         total -= buffer[i & STBTT__OVER_MASK];+         pixels[i] = (unsigned char) (total / kernel_width);+      }++      pixels += stride_in_bytes;+   }+}++static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)+{+   unsigned char buffer[STBTT_MAX_OVERSAMPLE];+   int safe_h = h - kernel_width;+   int j;+   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze+   for (j=0; j < w; ++j) {+      int i;+      unsigned int total;+      STBTT_memset(buffer, 0, kernel_width);++      total = 0;++      // make kernel_width a constant in common cases so compiler can optimize out the divide+      switch (kernel_width) {+         case 2:+            for (i=0; i <= safe_h; ++i) {+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];+               pixels[i*stride_in_bytes] = (unsigned char) (total / 2);+            }+            break;+         case 3:+            for (i=0; i <= safe_h; ++i) {+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];+               pixels[i*stride_in_bytes] = (unsigned char) (total / 3);+            }+            break;+         case 4:+            for (i=0; i <= safe_h; ++i) {+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];+               pixels[i*stride_in_bytes] = (unsigned char) (total / 4);+            }+            break;+         case 5:+            for (i=0; i <= safe_h; ++i) {+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];+               pixels[i*stride_in_bytes] = (unsigned char) (total / 5);+            }+            break;+         default:+            for (i=0; i <= safe_h; ++i) {+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];+               pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);+            }+            break;+      }++      for (; i < h; ++i) {+         STBTT_assert(pixels[i*stride_in_bytes] == 0);+         total -= buffer[i & STBTT__OVER_MASK];+         pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);+      }++      pixels += 1;+   }+}++static float stbtt__oversample_shift(int oversample)+{+   if (!oversample)+      return 0.0f;++   // The prefilter is a box filter of width "oversample",+   // which shifts phase by (oversample - 1)/2 pixels in+   // oversampled space. We want to shift in the opposite+   // direction to counter this.+   return (float)-(oversample - 1) / (2.0f * (float)oversample);+}++// rects array must be big enough to accommodate all characters in the given ranges+STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)+{+   int i,j,k;+   int missing_glyph_added = 0;++   k=0;+   for (i=0; i < num_ranges; ++i) {+      float fh = ranges[i].font_size;+      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);+      ranges[i].h_oversample = (unsigned char) spc->h_oversample;+      ranges[i].v_oversample = (unsigned char) spc->v_oversample;+      for (j=0; j < ranges[i].num_chars; ++j) {+         int x0,y0,x1,y1;+         int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];+         int glyph = stbtt_FindGlyphIndex(info, codepoint);+         if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {+            rects[k].w = rects[k].h = 0;+         } else {+            stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,+                                            scale * spc->h_oversample,+                                            scale * spc->v_oversample,+                                            0,0,+                                            &x0,&y0,&x1,&y1);+            rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);+            rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);+            if (glyph == 0)+               missing_glyph_added = 1;+         }+         ++k;+      }+   }++   return k;+}++STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)+{+   stbtt_MakeGlyphBitmapSubpixel(info,+                                 output,+                                 out_w - (prefilter_x - 1),+                                 out_h - (prefilter_y - 1),+                                 out_stride,+                                 scale_x,+                                 scale_y,+                                 shift_x,+                                 shift_y,+                                 glyph);++   if (prefilter_x > 1)+      stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);++   if (prefilter_y > 1)+      stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);++   *sub_x = stbtt__oversample_shift(prefilter_x);+   *sub_y = stbtt__oversample_shift(prefilter_y);+}++// rects array must be big enough to accommodate all characters in the given ranges+STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)+{+   int i,j,k, missing_glyph = -1, return_value = 1;++   // save current values+   int old_h_over = spc->h_oversample;+   int old_v_over = spc->v_oversample;++   k = 0;+   for (i=0; i < num_ranges; ++i) {+      float fh = ranges[i].font_size;+      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);+      float recip_h,recip_v,sub_x,sub_y;+      spc->h_oversample = ranges[i].h_oversample;+      spc->v_oversample = ranges[i].v_oversample;+      recip_h = 1.0f / spc->h_oversample;+      recip_v = 1.0f / spc->v_oversample;+      sub_x = stbtt__oversample_shift(spc->h_oversample);+      sub_y = stbtt__oversample_shift(spc->v_oversample);+      for (j=0; j < ranges[i].num_chars; ++j) {+         stbrp_rect *r = &rects[k];+         if (r->was_packed && r->w != 0 && r->h != 0) {+            stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];+            int advance, lsb, x0,y0,x1,y1;+            int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];+            int glyph = stbtt_FindGlyphIndex(info, codepoint);+            stbrp_coord pad = (stbrp_coord) spc->padding;++            // pad on left and top+            r->x += pad;+            r->y += pad;+            r->w -= pad;+            r->h -= pad;+            stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);+            stbtt_GetGlyphBitmapBox(info, glyph,+                                    scale * spc->h_oversample,+                                    scale * spc->v_oversample,+                                    &x0,&y0,&x1,&y1);+            stbtt_MakeGlyphBitmapSubpixel(info,+                                          spc->pixels + r->x + r->y*spc->stride_in_bytes,+                                          r->w - spc->h_oversample+1,+                                          r->h - spc->v_oversample+1,+                                          spc->stride_in_bytes,+                                          scale * spc->h_oversample,+                                          scale * spc->v_oversample,+                                          0,0,+                                          glyph);++            if (spc->h_oversample > 1)+               stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,+                                  r->w, r->h, spc->stride_in_bytes,+                                  spc->h_oversample);++            if (spc->v_oversample > 1)+               stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,+                                  r->w, r->h, spc->stride_in_bytes,+                                  spc->v_oversample);++            bc->x0       = (stbtt_int16)  r->x;+            bc->y0       = (stbtt_int16)  r->y;+            bc->x1       = (stbtt_int16) (r->x + r->w);+            bc->y1       = (stbtt_int16) (r->y + r->h);+            bc->xadvance =                scale * advance;+            bc->xoff     =       (float)  x0 * recip_h + sub_x;+            bc->yoff     =       (float)  y0 * recip_v + sub_y;+            bc->xoff2    =                (x0 + r->w) * recip_h + sub_x;+            bc->yoff2    =                (y0 + r->h) * recip_v + sub_y;++            if (glyph == 0)+               missing_glyph = j;+         } else if (spc->skip_missing) {+            return_value = 0;+         } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {+            ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];+         } else {+            return_value = 0; // if any fail, report failure+         }++         ++k;+      }+   }++   // restore original values+   spc->h_oversample = old_h_over;+   spc->v_oversample = old_v_over;++   return return_value;+}++STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)+{+   stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);+}++STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)+{+   stbtt_fontinfo info;+   int i,j,n, return_value = 1;+   //stbrp_context *context = (stbrp_context *) spc->pack_info;+   stbrp_rect    *rects;++   // flag all characters as NOT packed+   for (i=0; i < num_ranges; ++i)+      for (j=0; j < ranges[i].num_chars; ++j)+         ranges[i].chardata_for_range[j].x0 =+         ranges[i].chardata_for_range[j].y0 =+         ranges[i].chardata_for_range[j].x1 =+         ranges[i].chardata_for_range[j].y1 = 0;++   n = 0;+   for (i=0; i < num_ranges; ++i)+      n += ranges[i].num_chars;++   rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);+   if (rects == NULL)+      return 0;++   info.userdata = spc->user_allocator_context;+   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));++   n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);++   stbtt_PackFontRangesPackRects(spc, rects, n);++   return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);++   STBTT_free(rects, spc->user_allocator_context);+   return return_value;+}++STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,+            int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)+{+   stbtt_pack_range range;+   range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;+   range.array_of_unicode_codepoints = NULL;+   range.num_chars                   = num_chars_in_range;+   range.chardata_for_range          = chardata_for_range;+   range.font_size                   = font_size;+   return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);+}++STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)+{+   int i_ascent, i_descent, i_lineGap;+   float scale;+   stbtt_fontinfo info;+   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));+   scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);+   stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);+   *ascent  = (float) i_ascent  * scale;+   *descent = (float) i_descent * scale;+   *lineGap = (float) i_lineGap * scale;+}++STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)+{+   float ipw = 1.0f / pw, iph = 1.0f / ph;+   const stbtt_packedchar *b = chardata + char_index;++   if (align_to_integer) {+      float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);+      float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);+      q->x0 = x;+      q->y0 = y;+      q->x1 = x + b->xoff2 - b->xoff;+      q->y1 = y + b->yoff2 - b->yoff;+   } else {+      q->x0 = *xpos + b->xoff;+      q->y0 = *ypos + b->yoff;+      q->x1 = *xpos + b->xoff2;+      q->y1 = *ypos + b->yoff2;+   }++   q->s0 = b->x0 * ipw;+   q->t0 = b->y0 * iph;+   q->s1 = b->x1 * ipw;+   q->t1 = b->y1 * iph;++   *xpos += b->xadvance;+}++//////////////////////////////////////////////////////////////////////////////+//+// sdf computation+//++#define STBTT_min(a,b)  ((a) < (b) ? (a) : (b))+#define STBTT_max(a,b)  ((a) < (b) ? (b) : (a))++static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])+{+   float q0perp = q0[1]*ray[0] - q0[0]*ray[1];+   float q1perp = q1[1]*ray[0] - q1[0]*ray[1];+   float q2perp = q2[1]*ray[0] - q2[0]*ray[1];+   float roperp = orig[1]*ray[0] - orig[0]*ray[1];++   float a = q0perp - 2*q1perp + q2perp;+   float b = q1perp - q0perp;+   float c = q0perp - roperp;++   float s0 = 0., s1 = 0.;+   int num_s = 0;++   if (a != 0.0) {+      float discr = b*b - a*c;+      if (discr > 0.0) {+         float rcpna = -1 / a;+         float d = (float) STBTT_sqrt(discr);+         s0 = (b+d) * rcpna;+         s1 = (b-d) * rcpna;+         if (s0 >= 0.0 && s0 <= 1.0)+            num_s = 1;+         if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {+            if (num_s == 0) s0 = s1;+            ++num_s;+         }+      }+   } else {+      // 2*b*s + c = 0+      // s = -c / (2*b)+      s0 = c / (-2 * b);+      if (s0 >= 0.0 && s0 <= 1.0)+         num_s = 1;+   }++   if (num_s == 0)+      return 0;+   else {+      float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);+      float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;++      float q0d =   q0[0]*rayn_x +   q0[1]*rayn_y;+      float q1d =   q1[0]*rayn_x +   q1[1]*rayn_y;+      float q2d =   q2[0]*rayn_x +   q2[1]*rayn_y;+      float rod = orig[0]*rayn_x + orig[1]*rayn_y;++      float q10d = q1d - q0d;+      float q20d = q2d - q0d;+      float q0rd = q0d - rod;++      hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;+      hits[0][1] = a*s0+b;++      if (num_s > 1) {+         hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;+         hits[1][1] = a*s1+b;+         return 2;+      } else {+         return 1;+      }+   }+}++static int equal(float *a, float *b)+{+   return (a[0] == b[0] && a[1] == b[1]);+}++static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)+{+   int i;+   float orig[2], ray[2] = { 1, 0 };+   float y_frac;+   int winding = 0;++   orig[0] = x;+   orig[1] = y;++   // make sure y never passes through a vertex of the shape+   y_frac = (float) STBTT_fmod(y, 1.0f);+   if (y_frac < 0.01f)+      y += 0.01f;+   else if (y_frac > 0.99f)+      y -= 0.01f;+   orig[1] = y;++   // test a ray from (-infinity,y) to (x,y)+   for (i=0; i < nverts; ++i) {+      if (verts[i].type == STBTT_vline) {+         int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;+         int x1 = (int) verts[i  ].x, y1 = (int) verts[i  ].y;+         if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {+            float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;+            if (x_inter < x)+               winding += (y0 < y1) ? 1 : -1;+         }+      }+      if (verts[i].type == STBTT_vcurve) {+         int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;+         int x1 = (int) verts[i  ].cx, y1 = (int) verts[i  ].cy;+         int x2 = (int) verts[i  ].x , y2 = (int) verts[i  ].y ;+         int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));+         int by = STBTT_max(y0,STBTT_max(y1,y2));+         if (y > ay && y < by && x > ax) {+            float q0[2],q1[2],q2[2];+            float hits[2][2];+            q0[0] = (float)x0;+            q0[1] = (float)y0;+            q1[0] = (float)x1;+            q1[1] = (float)y1;+            q2[0] = (float)x2;+            q2[1] = (float)y2;+            if (equal(q0,q1) || equal(q1,q2)) {+               x0 = (int)verts[i-1].x;+               y0 = (int)verts[i-1].y;+               x1 = (int)verts[i  ].x;+               y1 = (int)verts[i  ].y;+               if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {+                  float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;+                  if (x_inter < x)+                     winding += (y0 < y1) ? 1 : -1;+               }+            } else {+               int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);+               if (num_hits >= 1)+                  if (hits[0][0] < 0)+                     winding += (hits[0][1] < 0 ? -1 : 1);+               if (num_hits >= 2)+                  if (hits[1][0] < 0)+                     winding += (hits[1][1] < 0 ? -1 : 1);+            }+         }+      }+   }+   return winding;+}++static float stbtt__cuberoot( float x )+{+   if (x<0)+      return -(float) STBTT_pow(-x,1.0f/3.0f);+   else+      return  (float) STBTT_pow( x,1.0f/3.0f);+}++// x^3 + c*x^2 + b*x + a = 0+static int stbtt__solve_cubic(float a, float b, float c, float* r)+{+	float s = -a / 3;+	float p = b - a*a / 3;+	float q = a * (2*a*a - 9*b) / 27 + c;+   float p3 = p*p*p;+	float d = q*q + 4*p3 / 27;+	if (d >= 0) {+		float z = (float) STBTT_sqrt(d);+		float u = (-q + z) / 2;+		float v = (-q - z) / 2;+		u = stbtt__cuberoot(u);+		v = stbtt__cuberoot(v);+		r[0] = s + u + v;+		return 1;+	} else {+	   float u = (float) STBTT_sqrt(-p/3);+	   float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative+	   float m = (float) STBTT_cos(v);+      float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;+	   r[0] = s + u * 2 * m;+	   r[1] = s - u * (m + n);+	   r[2] = s - u * (m - n);++      //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f);  // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?+      //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);+      //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);+   	return 3;+   }+}++STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)+{+   float scale_x = scale, scale_y = scale;+   int ix0,iy0,ix1,iy1;+   int w,h;+   unsigned char *data;++   if (scale == 0) return NULL;++   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);++   // if empty, return NULL+   if (ix0 == ix1 || iy0 == iy1)+      return NULL;++   ix0 -= padding;+   iy0 -= padding;+   ix1 += padding;+   iy1 += padding;++   w = (ix1 - ix0);+   h = (iy1 - iy0);++   if (width ) *width  = w;+   if (height) *height = h;+   if (xoff  ) *xoff   = ix0;+   if (yoff  ) *yoff   = iy0;++   // invert for y-downwards bitmaps+   scale_y = -scale_y;++   {+      int x,y,i,j;+      float *precompute;+      stbtt_vertex *verts;+      int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);+      data = (unsigned char *) STBTT_malloc(w * h, info->userdata);+      precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);++      for (i=0,j=num_verts-1; i < num_verts; j=i++) {+         if (verts[i].type == STBTT_vline) {+            float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;+            float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;+            float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));+            precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;+         } else if (verts[i].type == STBTT_vcurve) {+            float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;+            float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;+            float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;+            float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;+            float len2 = bx*bx + by*by;+            if (len2 != 0.0f)+               precompute[i] = 1.0f / (bx*bx + by*by);+            else+               precompute[i] = 0.0f;+         } else+            precompute[i] = 0.0f;+      }++      for (y=iy0; y < iy1; ++y) {+         for (x=ix0; x < ix1; ++x) {+            float val;+            float min_dist = 999999.0f;+            float sx = (float) x + 0.5f;+            float sy = (float) y + 0.5f;+            float x_gspace = (sx / scale_x);+            float y_gspace = (sy / scale_y);++            int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path++            for (i=0; i < num_verts; ++i) {+               float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;++               // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve+               float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);+               if (dist2 < min_dist*min_dist)+                  min_dist = (float) STBTT_sqrt(dist2);++               if (verts[i].type == STBTT_vline) {+                  float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;++                  // coarse culling against bbox+                  //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&+                  //    sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)+                  float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];+                  STBTT_assert(i != 0);+                  if (dist < min_dist) {+                     // check position along line+                     // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)+                     // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)+                     float dx = x1-x0, dy = y1-y0;+                     float px = x0-sx, py = y0-sy;+                     // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy+                     // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve+                     float t = -(px*dx + py*dy) / (dx*dx + dy*dy);+                     if (t >= 0.0f && t <= 1.0f)+                        min_dist = dist;+                  }+               } else if (verts[i].type == STBTT_vcurve) {+                  float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;+                  float x1 = verts[i  ].cx*scale_x, y1 = verts[i  ].cy*scale_y;+                  float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);+                  float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);+                  float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);+                  float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);+                  // coarse culling against bbox to avoid computing cubic unnecessarily+                  if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {+                     int num=0;+                     float ax = x1-x0, ay = y1-y0;+                     float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;+                     float mx = x0 - sx, my = y0 - sy;+                     float res[3],px,py,t,it;+                     float a_inv = precompute[i];+                     if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula+                        float a = 3*(ax*bx + ay*by);+                        float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);+                        float c = mx*ax+my*ay;+                        if (a == 0.0) { // if a is 0, it's linear+                           if (b != 0.0) {+                              res[num++] = -c/b;+                           }+                        } else {+                           float discriminant = b*b - 4*a*c;+                           if (discriminant < 0)+                              num = 0;+                           else {+                              float root = (float) STBTT_sqrt(discriminant);+                              res[0] = (-b - root)/(2*a);+                              res[1] = (-b + root)/(2*a);+                              num = 2; // don't bother distinguishing 1-solution case, as code below will still work+                           }+                        }+                     } else {+                        float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point+                        float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;+                        float d = (mx*ax+my*ay) * a_inv;+                        num = stbtt__solve_cubic(b, c, d, res);+                     }+                     if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {+                        t = res[0], it = 1.0f - t;+                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;+                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;+                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);+                        if (dist2 < min_dist * min_dist)+                           min_dist = (float) STBTT_sqrt(dist2);+                     }+                     if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {+                        t = res[1], it = 1.0f - t;+                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;+                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;+                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);+                        if (dist2 < min_dist * min_dist)+                           min_dist = (float) STBTT_sqrt(dist2);+                     }+                     if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {+                        t = res[2], it = 1.0f - t;+                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;+                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;+                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);+                        if (dist2 < min_dist * min_dist)+                           min_dist = (float) STBTT_sqrt(dist2);+                     }+                  }+               }+            }+            if (winding == 0)+               min_dist = -min_dist;  // if outside the shape, value is negative+            val = onedge_value + pixel_dist_scale * min_dist;+            if (val < 0)+               val = 0;+            else if (val > 255)+               val = 255;+            data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;+         }+      }+      STBTT_free(precompute, info->userdata);+      STBTT_free(verts, info->userdata);+   }+   return data;+}++STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)+{+   return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);+}++STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)+{+   STBTT_free(bitmap, userdata);+}++//////////////////////////////////////////////////////////////////////////////+//+// font name matching -- recommended not to use this+//++// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string+static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)+{+   stbtt_int32 i=0;++   // convert utf16 to utf8 and compare the results while converting+   while (len2) {+      stbtt_uint16 ch = s2[0]*256 + s2[1];+      if (ch < 0x80) {+         if (i >= len1) return -1;+         if (s1[i++] != ch) return -1;+      } else if (ch < 0x800) {+         if (i+1 >= len1) return -1;+         if (s1[i++] != 0xc0 + (ch >> 6)) return -1;+         if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;+      } else if (ch >= 0xd800 && ch < 0xdc00) {+         stbtt_uint32 c;+         stbtt_uint16 ch2 = s2[2]*256 + s2[3];+         if (i+3 >= len1) return -1;+         c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;+         if (s1[i++] != 0xf0 + (c >> 18)) return -1;+         if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;+         if (s1[i++] != 0x80 + ((c >>  6) & 0x3f)) return -1;+         if (s1[i++] != 0x80 + ((c      ) & 0x3f)) return -1;+         s2 += 2; // plus another 2 below+         len2 -= 2;+      } else if (ch >= 0xdc00 && ch < 0xe000) {+         return -1;+      } else {+         if (i+2 >= len1) return -1;+         if (s1[i++] != 0xe0 + (ch >> 12)) return -1;+         if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;+         if (s1[i++] != 0x80 + ((ch     ) & 0x3f)) return -1;+      }+      s2 += 2;+      len2 -= 2;+   }+   return i;+}++static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)+{+   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);+}++// returns results in whatever encoding you request... but note that 2-byte encodings+// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare+STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)+{+   stbtt_int32 i,count,stringOffset;+   stbtt_uint8 *fc = font->data;+   stbtt_uint32 offset = font->fontstart;+   stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");+   if (!nm) return NULL;++   count = ttUSHORT(fc+nm+2);+   stringOffset = nm + ttUSHORT(fc+nm+4);+   for (i=0; i < count; ++i) {+      stbtt_uint32 loc = nm + 6 + 12 * i;+      if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)+          && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {+         *length = ttUSHORT(fc+loc+8);+         return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));+      }+   }+   return NULL;+}++static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)+{+   stbtt_int32 i;+   stbtt_int32 count = ttUSHORT(fc+nm+2);+   stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);++   for (i=0; i < count; ++i) {+      stbtt_uint32 loc = nm + 6 + 12 * i;+      stbtt_int32 id = ttUSHORT(fc+loc+6);+      if (id == target_id) {+         // find the encoding+         stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);++         // is this a Unicode encoding?+         if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {+            stbtt_int32 slen = ttUSHORT(fc+loc+8);+            stbtt_int32 off = ttUSHORT(fc+loc+10);++            // check if there's a prefix match+            stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);+            if (matchlen >= 0) {+               // check for target_id+1 immediately following, with same encoding & language+               if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {+                  slen = ttUSHORT(fc+loc+12+8);+                  off = ttUSHORT(fc+loc+12+10);+                  if (slen == 0) {+                     if (matchlen == nlen)+                        return 1;+                  } else if (matchlen < nlen && name[matchlen] == ' ') {+                     ++matchlen;+                     if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))+                        return 1;+                  }+               } else {+                  // if nothing immediately following+                  if (matchlen == nlen)+                     return 1;+               }+            }+         }++         // @TODO handle other encodings+      }+   }+   return 0;+}++static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)+{+   stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);+   stbtt_uint32 nm,hd;+   if (!stbtt__isfont(fc+offset)) return 0;++   // check italics/bold/underline flags in macStyle...+   if (flags) {+      hd = stbtt__find_table(fc, offset, "head");+      if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;+   }++   nm = stbtt__find_table(fc, offset, "name");+   if (!nm) return 0;++   if (flags) {+      // if we checked the macStyle flags, then just check the family and ignore the subfamily+      if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))  return 1;+      if (stbtt__matchpair(fc, nm, name, nlen,  1, -1))  return 1;+      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;+   } else {+      if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))  return 1;+      if (stbtt__matchpair(fc, nm, name, nlen,  1,  2))  return 1;+      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;+   }++   return 0;+}++static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags)+{+   stbtt_int32 i;+   for (i=0;;++i) {+      stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);+      if (off < 0) return off;+      if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))+         return off;+   }+}++#if defined(__GNUC__) || defined(__clang__)+#pragma GCC diagnostic push+#pragma GCC diagnostic ignored "-Wcast-qual"+#endif++STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,+                                float pixel_height, unsigned char *pixels, int pw, int ph,+                                int first_char, int num_chars, stbtt_bakedchar *chardata)+{+   return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);+}++STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)+{+   return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);+}++STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)+{+   return stbtt_GetNumberOfFonts_internal((unsigned char *) data);+}++STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)+{+   return stbtt_InitFont_internal(info, (unsigned char *) data, offset);+}++STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)+{+   return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);+}++STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)+{+   return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);+}++#if defined(__GNUC__) || defined(__clang__)+#pragma GCC diagnostic pop+#endif++#endif // STB_TRUETYPE_IMPLEMENTATION+++// FULL VERSION HISTORY+//+//   1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod+//   1.18 (2018-01-29) add missing function+//   1.17 (2017-07-23) make more arguments const; doc fix+//   1.16 (2017-07-12) SDF support+//   1.15 (2017-03-03) make more arguments const+//   1.14 (2017-01-16) num-fonts-in-TTC function+//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts+//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual+//   1.11 (2016-04-02) fix unused-variable warning+//   1.10 (2016-04-02) allow user-defined fabs() replacement+//                     fix memory leak if fontsize=0.0+//                     fix warning from duplicate typedef+//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges+//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges+//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;+//                     allow PackFontRanges to pack and render in separate phases;+//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);+//                     fixed an assert() bug in the new rasterizer+//                     replace assert() with STBTT_assert() in new rasterizer+//   1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)+//                     also more precise AA rasterizer, except if shapes overlap+//                     remove need for STBTT_sort+//   1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC+//   1.04 (2015-04-15) typo in example+//   1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes+//   1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C+++//   1.01 (2014-12-08) fix subpixel position when oversampling to exactly match+//                        non-oversampled; STBTT_POINT_SIZE for packed case only+//   1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling+//   0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg)+//   0.9  (2014-08-07) support certain mac/iOS fonts without an MS platformID+//   0.8b (2014-07-07) fix a warning+//   0.8  (2014-05-25) fix a few more warnings+//   0.7  (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back+//   0.6c (2012-07-24) improve documentation+//   0.6b (2012-07-20) fix a few more warnings+//   0.6  (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,+//                        stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty+//   0.5  (2011-12-09) bugfixes:+//                        subpixel glyph renderer computed wrong bounding box+//                        first vertex of shape can be off-curve (FreeSans)+//   0.4b (2011-12-03) fixed an error in the font baking example+//   0.4  (2011-12-01) kerning, subpixel rendering (tor)+//                    bugfixes for:+//                        codepoint-to-glyph conversion using table fmt=12+//                        codepoint-to-glyph conversion using table fmt=4+//                        stbtt_GetBakedQuad with non-square texture (Zer)+//                    updated Hello World! sample to use kerning and subpixel+//                    fixed some warnings+//   0.3  (2009-06-24) cmap fmt=12, compound shapes (MM)+//                    userdata, malloc-from-userdata, non-zero fill (stb)+//   0.2  (2009-03-11) Fix unsigned/signed char warnings+//   0.1  (2009-03-09) First public release+//++/*+------------------------------------------------------------------------------+This software is available under 2 licenses -- choose whichever you prefer.+------------------------------------------------------------------------------+ALTERNATIVE A - MIT License+Copyright (c) 2017 Sean Barrett+Permission is hereby granted, free of charge, to any person obtaining a copy of+this software and associated documentation files (the "Software"), to deal in+the Software without restriction, including without limitation the rights to+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies+of the Software, and to permit persons to whom the Software is furnished to do+so, subject to the following conditions:+The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.+------------------------------------------------------------------------------+ALTERNATIVE B - Public Domain (www.unlicense.org)+This is free and unencumbered software released into the public domain.+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this+software, either in source code form or as a compiled binary, for any purpose,+commercial or non-commercial, and by any means.+In jurisdictions that recognize copyright laws, the author or authors of this+software dedicate any and all copyright interest in the software to the public+domain. We make this dedication for the benefit of the public at large and to+the detriment of our heirs and successors. We intend this dedication to be an+overt act of relinquishment in perpetuity of all present and future rights to+this software under copyright law.+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.+------------------------------------------------------------------------------+*/
src/NanoVG.hs view
@@ -86,15 +86,28 @@   , arc   , rect   , roundedRect+  , roundedRectVarying   , ellipse   , circle   , fill   , stroke+  -- * Global Composite+  , BlendFactor(..)+  , CompositeOperation(..)+  , globalCompositeOperation+  , globalCompositeBlendFunc+  , globalCompositeBlendFuncSeparate   -- * Text   , Font(..)   , createFont+  , createFontAtIndex   , createFontMem+  , createFontMemAtIndex   , findFont+  , addFallbackFontId+  , addFallbackFont+  , resetFallbackFontsId+  , resetFallbackFonts   , fontSize   , fontBlur   , textLetterSpacing
src/NanoVG/Internal.chs view
@@ -85,10 +85,17 @@   , arc   , rect   , roundedRect+  , roundedRectVarying   , ellipse   , circle   , fill   , stroke+  -- * Global Composite+  , BlendFactor(..)+  , CompositeOperation(..)+  , globalCompositeOperation+  , globalCompositeBlendFunc+  , globalCompositeBlendFuncSeparate   -- * Vector types   , V2(..)   , V3(..)@@ -101,6 +108,7 @@ import NanoVG.Internal.Color import NanoVG.Internal.Context import NanoVG.Internal.FixedVector+import NanoVG.Internal.GlobalComposite import NanoVG.Internal.Image import NanoVG.Internal.Paint import NanoVG.Internal.Path@@ -130,7 +138,7 @@ -- frame buffer size. In that case you would set windowWidth/Height to the window size -- devicePixelRatio to: frameBufferWidth / windowWidth. {#fun unsafe nvgBeginFrame as beginFrame-        {`Context',`CInt',`CInt',`Float'} -> `()'#}+        {`Context',`Float',`Float',`Float'} -> `()'#}  -- | Cancels drawing the current frame. {#fun unsafe nvgCancelFrame as cancelFrame
+ src/NanoVG/Internal/GlobalComposite.chs view
@@ -0,0 +1,36 @@+module NanoVG.Internal.GlobalComposite where++import NanoVG.Internal.Context++#include "nanovg.h"++{#pointer *NVGcontext as Context newtype nocode#}++{#enum NVGblendFactor as BlendFactor+         {underscoreToCase} with prefix = "NVG_"+         deriving (Show,Read,Eq,Ord)#}++{#enum NVGcompositeOperation as CompositeOperation+         {underscoreToCase} with prefix = "NVG_"+         deriving (Show,Read,Eq,Ord)#}++-- | Composite operation+--+-- The composite operations in NanoVG are modeled after HTML Canvas API, and+-- the blend func is based on OpenGL (see corresponding manuals for more info).+-- The colors in the blending state have premultiplied alpha.++-- | Sets the composite operation. The op parameter should be one of+-- NVGcompositeOperation.+{#fun unsafe nvgGlobalCompositeOperation as globalCompositeOperation+        {`Context',`CompositeOperation'} -> `()'#}++-- | Sets the composite operation with custom pixel arithmetic. The parameters+-- should be one of NVGblendFactor.+{#fun unsafe nvgGlobalCompositeBlendFunc as globalCompositeBlendFunc+        {`Context',`BlendFactor', `BlendFactor'} -> `()'#}++-- | Sets the composite operation with custom pixel arithmetic for RGB and alpha+-- components separately. The parameters should be one of NVGblendFactor.+{#fun unsafe nvgGlobalCompositeBlendFuncSeparate as globalCompositeBlendFuncSeparate+        {`Context',`BlendFactor', `BlendFactor', `BlendFactor', `BlendFactor'} -> `()'#}
src/NanoVG/Internal/Path.chs view
@@ -50,13 +50,19 @@ {#fun unsafe nvgArc as arc         {`Context',`CFloat',`CFloat', `CFloat', `CFloat', `CFloat', `Winding'} -> `()'#} --- | Creates new rectangle shaped sub-path.+-- | Creates new rectangle shaped sub-path. Receives x, y, w and h {#fun unsafe nvgRect as rect          {`Context',`CFloat',`CFloat',`CFloat',`CFloat'} -> `()'#} --- | Creates new rounded rectangle shaped sub-path.+-- | Creates new rounded rectangle shaped sub-path. In addition to x, y, w and h, it receives+-- | r, indicating the radius (equal in all corners) {#fun unsafe nvgRoundedRect as roundedRect         {`Context',`CFloat',`CFloat',`CFloat',`CFloat',`CFloat'} -> `()'#}++-- | Creates new rounded rectangle shaped sub-path. In addition to x, y, w and h, it receives+-- | rtl, rtr, rbr, rbl, the radius of each corner in clockwise order starting from top left+{#fun unsafe nvgRoundedRectVarying as roundedRectVarying+        {`Context',`CFloat',`CFloat',`CFloat',`CFloat',`CFloat',`CFloat',`CFloat',`CFloat'} -> `()'#}  -- | Creates new ellipse shaped sub-path. {#fun unsafe nvgEllipse as ellipse
src/NanoVG/Internal/Text.chs view
@@ -99,14 +99,42 @@ {#fun unsafe nvgCreateFont as createFont         {`Context',withCString*`T.Text','withCString.unwrapFileName'*`FileName'} -> `Maybe Font'safeFont#} +-- | Creates font by loading it from the disk from specified file name.+-- fontIndex specifies which font face to load from a .ttf/.ttc file.+-- Returns handle to the font.+{#fun unsafe nvgCreateFontAtIndex as createFontAtIndex+        {`Context',withCString*`T.Text','withCString.unwrapFileName'*`FileName', `CInt'} -> `Maybe Font'safeFont#}+ -- | Creates image by loading it from the specified memory chunk. -- Returns handle to the font. {#fun unsafe nvgCreateFontMem as createFontMem         {`Context',withCString*`T.Text',useAsCStringLen'*`ByteString'&,zero-`CInt'} -> `Maybe Font'safeFont#} +-- | Creates image by loading it from the specified memory chunk.+-- fontIndex specifies which font face to load from a .ttf/.ttc file.+-- Returns handle to the font.+{#fun unsafe nvgCreateFontMemAtIndex as createFontMemAtIndex+        {`Context',withCString*`T.Text',useAsCStringLen'*`ByteString'&,zero-`CInt',`CInt'} -> `Maybe Font'safeFont#}+ -- | Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found. {#fun unsafe nvgFindFont as findFont         {`Context', withCString*`T.Text'} -> `Maybe Font'safeFont#}++-- | Adds a fallback font by handle.+{#fun unsafe nvgAddFallbackFontId as addFallbackFontId+        {`Context',`CInt',`CInt'} -> `Maybe Font'safeFont#}++-- | Adds a fallback font by name.+{#fun unsafe nvgAddFallbackFont as addFallbackFont+        {`Context',withCString*`T.Text',withCString*`T.Text'} -> `Maybe Font'safeFont#}++-- | Resets fallback fonts by handle.+{#fun unsafe nvgResetFallbackFontsId as resetFallbackFontsId+        {`Context',`CInt'} -> `()'#}++-- | Resets fallback fonts by name.+{#fun unsafe nvgResetFallbackFonts as resetFallbackFonts+        {`Context',withCString*`T.Text'} -> `()'#}  -- | Sets the font size of current text style. {#fun unsafe nvgFontSize as fontSize