static bool ProcessFace(FT_Face& face, const string& filename, u32 fontHeight)
{
	string imageName;
	string specsName;
	if (!outputFileName.empty()) {
		imageName = outputFileName + ".png";
		specsName = outputFileName + ".lua";
	}
	else {
		string basename = filename;
		const string::size_type lastOf = filename.find_last_of('.');
		if (lastOf != string::npos) {
			basename = filename.substr(0, lastOf);
			if (debugLevel >= 1) {
				logOutput.Print("basename = %s\n", basename.c_str());
			}
		}
		char heightText[64];
		sprintf(heightText, "_%i", fontHeight);
		char outlineText[64];
		sprintf(outlineText, "_%i", outlineRadius);
		imageName = basename + heightText + ".png";
		specsName = basename + heightText + ".lua";
	}

	logOutput.Print("Processing %s @ %i\n", filename.c_str(), fontHeight);
	if (debugLevel >= 1) {
		PrintFaceInfo(face);
	}

	u32 maxPixelXsize = 0;
	u32 maxPixelYsize = 0;

	for (u32 g = minChar; g <= maxChar; g++) {
		Glyph* glyph = new Glyph(face, g);
		if (!glyph->valid) {
			continue;
		}
		glyphs.push_back(glyph);

		if (outlineRadius> 0) {
			glyph->Outline(outlineRadius);
		}
		if (debugLevel >= 2) {
			PrintGlyphInfo(face->glyph, g);
		}
		if (maxPixelXsize < glyph->xsize) {
			maxPixelXsize = glyph->xsize;
		}
		if (maxPixelYsize < glyph->ysize) {
			maxPixelYsize = glyph->ysize;
		}
	}

	const u32 xskip = maxPixelXsize + (2 * (padding + stuffing));
	const u32 yskip = maxPixelYsize + (2 * (padding + stuffing));
	const u32 xdivs = (xTexSize / xskip);
	const u32 ydivs = ((maxChar - minChar + 1) / xdivs) + 1;

	yTexSize = ydivs * yskip;
	u32 binSize = 1;
	while (binSize < yTexSize) {
		binSize = binSize << 1;
	}
	yTexSize = binSize;

	if (debugLevel >= 1) {
		logOutput.Print("xTexSize = %i\n", xTexSize);
		logOutput.Print("yTexSize = %i\n", yTexSize);
		logOutput.Print("xdivs = %i\n", xdivs);
		logOutput.Print("ydivs = %i\n", ydivs);
		logOutput.Print("maxPixelXsize = %i\n", maxPixelXsize);
		logOutput.Print("maxPixelYsize = %i\n", maxPixelYsize);
	}

	FILE* specFile = fopen(specsName.c_str(), "wt");
	if (specFile == NULL) {
		logOutput.Print("%s: %s\n", specsName.c_str(), strerror(errno));
		return false;
	}

	u32 yStep;
	if (FT_IS_SCALABLE(face)) {
		yStep = (fontHeight * face->height) / face->units_per_EM;
	} else {
		yStep = (face->height / 64);
		if (yStep == 0) {
      // some fonts do not provide a face->height, so make one up
			yStep = (5 * fontHeight) / 4;
		}
	}

	fprintf(specFile, "\n");
	fprintf(specFile, "local fontSpecs = {\n");
	fprintf(specFile, "  srcFile  = [[%s]],\n", filename.c_str());
	fprintf(specFile, "  family   = [[%s]],\n", face->family_name);
	fprintf(specFile, "  style    = [[%s]],\n", face->style_name);
	fprintf(specFile, "  yStep    = %i,\n", yStep);
	fprintf(specFile, "  height   = %i,\n", fontHeight);
	fprintf(specFile, "  xTexSize = %i,\n", xTexSize);
	fprintf(specFile, "  yTexSize = %i,\n", yTexSize);
	fprintf(specFile, "  outlineRadius = %i,\n", outlineRadius);
	fprintf(specFile, "  outlineWeight = %i,\n", outlineWeight);
	fprintf(specFile, "}\n");
	fprintf(specFile, "\n");
	fprintf(specFile, "local glyphs = {}\n");
	fprintf(specFile, "\n");

	ILuint img;
	ilGenImages(1, &img);
	if (img == 0) {
		logOutput.Print("ERROR: ilGenImages() == 0\n");
		return false;
	}
	ilBindImage(img);

	ilTexImage(xTexSize, yTexSize, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
	ilClearColor(1.0f, 1.0f, 1.0f, 0.0f);
	ilClearImage();

	u32 xcell = 0;
	u32 ycell = 0;
	for (int g = 0; g < (int)glyphs.size(); g++) {
		Glyph* glyph = glyphs[g];
		const u32 txOffset = (xcell * xskip) + (padding + stuffing);
		const u32 tyOffset = (ycell * yskip) + (padding + stuffing);
		ilSetPixels(
								txOffset, tyOffset, 0,
				glyph->xsize, glyph->ysize, 1,
		IL_RGBA, IL_UNSIGNED_BYTE, glyph->pixels
							 );
		glyph->txn += txOffset;
		glyph->tyn += tyOffset;
		glyph->txp += txOffset;
		glyph->typ += tyOffset;
		glyph->SaveSpecs(specFile);

		if (debugLevel >= 2) {
			PrintGlyphInfo(face->glyph, g);
		}

		xcell++;
		if (xcell >= xdivs) {
			xcell = 0;
			ycell++;
		}
	}

	fprintf(specFile, "\n");
	fprintf(specFile, "fontSpecs.glyphs = glyphs\n");
	fprintf(specFile, "\n");
	fprintf(specFile, "return fontSpecs\n");
	fprintf(specFile, "\n");

	fclose(specFile);
	logOutput.Print("Saved: %s\n", specsName.c_str());

	ilEnable(IL_FILE_OVERWRITE);
	ilHint(IL_COMPRESSION_HINT, IL_USE_COMPRESSION);
	ilSetInteger(IL_PNG_INTERLACE, 0);
	ilSetString(IL_PNG_TITLE_STRING, imageName.c_str());
	ilSetString(IL_PNG_AUTHNAME_STRING, "FontTexture");
	ilSetString(IL_PNG_DESCRIPTION_STRING,
							(outlineRadius> 0) ? "outlined" : "plain");
	ilSaveImage((char*)imageName.c_str());
	ilDisable(IL_FILE_OVERWRITE);
	logOutput.Print("Saved: %s\n", imageName.c_str());

	ilDeleteImages(1, &img);

	return true;
}