graphicc – Scalable Fonts

The initial text support in graphicc was based on some fixed sized bitmap fonts.  That’s a good starting point, and good enough for a lot of UI work, and perhaps even some simple graphs.  But it’s a less satisfying answer when you really want to get into the nitty gritty of things.

HellaWerld

Here’s the segoeui.ttf font being displayed in the current graphicc .  Why display in such an unreadable way?  To emphasize that it looks pretty smooth if you don’t look too close…

When it comes to truetype font rendering, the most common goto source is probably the freetype library.  It does a great job, has existed forever, and is used by everyone who doesn’t want to roll their own.  It does great rendering, using the hinting found in the truetype font files and all that.  All that greatness comes at a cost though.  The freetype library is a bit largish for such a small library as graphicc.  So, I went with a different approach.

Here I’m leveraging the stb_trutype.h file found in the public domain stb codes.  The library is good enough to render what you see here, using any of the truetype fonts found on your system.  It won’t do all the fancy things that freetype will, but it at least gives you access to the bulk of the font information, so you can do simple things like kerning.

Whats more, you get access to all the vertex information, so if you want to, you can actually render polygon outlines and the like, and not just take the pre-rendered bitmaps that it offers up.  In fact, one of the strongest parts of these routines is the polygon rendering code.  It makes sense to lift this code up and make it the general polygon rendering code for the entirety of graphicc.  At the moment, there are two or three polygon renderers in the codebase (including samples).  Having one routine which is compact, and capable of dealing with text, and anything else less complex than that, would be a big win for a tiny library such as this.  It will take some work to refactor in such a way that this can become a reality, but it’s probably well worth the effort.

Another benefit of that separation will be the fact that I’ll be able to apply a transform to the vertices for a glyph, and do the cheesy rotated text tricks.
Curious about the code? It’s roughly this

struct ttfset fontset;
struct stbtt_fontinfo finfo;

void setup()
{
	size(1024, 768);

	//char *filename = "c:/windows/fonts/arial.ttf";
	char *filename = "c:/windows/fonts/segoeui.ttf";

	if (!ttfset_open(fontset, filename)) {
		return ;
	}

	finfo = ttfset_font_from_index(fontset, 0);
}

void drawText()
{
	int i, j;
	int ascent, descent, lineGap, baseline;
	float scale, xpos = 2; // leave a little padding in case the character extends left
	float ypos = 2;

	char *text = "Hella Werld!";
	unsigned char *bitmap;

	stbtt_GetFontVMetrics(&finfo, &ascent, &descent, &lineGap);

	for (int pixfactor = 3; pixfactor < 9; pixfactor++) {

		int pixsize = pow((float)2, pixfactor);
		scale = stbtt_ScaleForPixelHeight(&finfo, pixsize);
		baseline = (int)(ascent*scale);

		int idx = 0;
		while (text[idx]) {
			int advance, lsb, x0, y0, x1, y1;
			float x_shift = xpos - (float)floor(xpos);
			stbtt_GetCodepointHMetrics(&finfo, text[idx], &advance, &lsb);
			stbtt_GetCodepointBitmapBoxSubpixel(&finfo, text[idx], scale, scale, x_shift, 0, &x0, &y0, &x1, &y1);

			int w, h;
			bitmap = stbtt_GetCodepointBitmap(&finfo, 0, scale, text[idx], &w, &h, 0, 0);

			raster_rgba_blend_alphamap(gpb, xpos, ypos + baseline + y0, bitmap, w, h, pYellow);

			//printf("%d %d %d", baseline, y0, y1);
			xpos += (advance * scale);
			if (text[idx + 1])
				xpos += scale*stbtt_GetCodepointKernAdvance(&finfo, text[idx], text[idx + 1]);
			idx++;

			stbtt_FreeBitmap(bitmap, NULL);
		}
		xpos = 2;
		ypos += pixsize-(scale*descent);
	}
}

It’s a bit wasteful in that a new glyph bitmap is created for every single character, even if they repeat, so there’s no caching of those bitmaps going on. If this were a real app, I’d be caching those bitmaps whenever I created them for a particular size.

The primary addition to the graphicc core is the rgba_blend_alphamap() function. It takes the 256 value alpha image generated for a glyph, and copies it to the destination, using the specified color, and the bitmap as the alpha value of the color as it does it. This makes for some nice anti-aliasing, which helps make the thing look smooth.

Well, there you have it. The font support is improving, without dragging in the kitchen sink. It may be possible that graphicc is able to stick to a very slender memory footprint and offer serious enough features.

Advertisements


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s