Pixel art of metremblin's Blog...

Font library code

2026-05-13

Example of how to use the x_info functions to add/get access to assets. This is the full font library including the font_info function. All the other assets are basically identical, except the struct stored in the black box may have more information (see headers.)

// All of the predefined assets have a x_info that is almost identical to this.
// The type returned can be viewed in the header files
Font_Info *font_info(Program *prg)
{
	Font_Info *info = (Font_Info *)booboo::get_black_box(prg, "com.nooskewl.booboo.font");
	if (info == nullptr) {
		info = new Font_Info;
		info->font_id = 0;
		booboo::set_black_box(prg, "com.nooskewl.booboo.font", info);
	}
	return info;
}

// The main magic is in the load/create functions, which stuffs a value into the black box
// and returns a handle
static void exprfunc_font_load(Program *prg, const std::vector<Token> &v)
{
	MIN_ARGS(3)

	std::string name = as_string(prg, v[0]);
	int size = as_number(prg, v[1]);
	bool smooth = as_number(prg, v[2]);

	Font_Info *info = font_info(prg);

	int sheet_size = 512;
	if (v.size() > 3) {
		sheet_size = as_number(prg, v[3]);
	}

	bool load_from_filesystem = false;
	if (v.size() > 4) {
		load_from_filesystem = as_number(prg, v[4]);
	}

	prg->result.type = Variable::NUMBER;

	try {
		gfx::TTF *font = new gfx::TTF(name, size, sheet_size, load_from_filesystem);
		font->set_smooth(smooth);
		prg->result.n = info->font_id;
		info->fonts[info->font_id++] = font;
	}
	catch (util::Error &e) {
		prg->result.n = -1;
	}
}

// These functions just access the info struct with a handle
static bool fontfunc_destroy(Program *prg, const std::vector<Token> &v)
{
	COUNT_ARGS(1)

	int id = as_number(prg, v[0]);
	Font_Info *info = font_info(prg);
	INFO_EXISTS(info->fonts, id)
	delete info->fonts[id];
	info->fonts.erase(info->fonts.find(id));

	return true;
}

static bool fontfunc_draw(Program *prg, const std::vector<Token> &v)
{
	MIN_ARGS(8)

	int id = as_number(prg, v[0]);
	double r = as_number(prg, v[1]);
	double g = as_number(prg, v[2]);
	double b = as_number(prg, v[3]);
	double a = as_number(prg, v[4]);
	std::string text = as_string(prg, v[5]);
	double x = as_number(prg, v[6]);
	double y = as_number(prg, v[7]);
	bool interpret_codes;
	bool rtl;

	if (v.size() > 8) {
		interpret_codes = as_number(prg, v[8]);
	}
	else {
		interpret_codes = false;
	}

	if (v.size() > 9) {
		rtl = as_number(prg, v[9]);
	}
	else {
		rtl = false;
	}

	Font_Info *info = font_info(prg);

	INFO_EXISTS(info->fonts, id)

	gfx::TTF *font = info->fonts[id];

	SDL_Color c;
	c.r = r;
	c.g = g;
	c.b = b;
	c.a = a;

	font->draw(c, text, util::Point<float>(x, y), interpret_codes, false, interpret_codes, rtl);

	return true;
}

static void exprfunc_font_width(Program *prg, const std::vector<Token> &v)
{
	COUNT_ARGS(2)

	int id = as_number(prg, v[0]);
	std::string text = as_string(prg, v[1]);
	
	Font_Info *info = font_info(prg);

	INFO_EXISTS(info->fonts, id)

	gfx::TTF *font = info->fonts[id];

	int w = font->get_text_width(text);

	prg->result.type = Variable::NUMBER;
	prg->result.n = w;
}

static void exprfunc_font_height(Program *prg, const std::vector<Token> &v)
{
	COUNT_ARGS(1)

	int id = as_number(prg, v[0]);
	
	Font_Info *info = font_info(prg);

	INFO_EXISTS(info->fonts, id)

	gfx::TTF *font = info->fonts[id];

	int h = font->get_height();

	prg->result.type = Variable::NUMBER;
	prg->result.n = h;
}

static bool fontfunc_add_extra_glyph(Program *prg, const std::vector<Token> &v)
{
	COUNT_ARGS(3)

	int id = as_number(prg, v[0]);
	int glyph_id = as_number(prg, v[1]);
	int image_id = as_number(prg, v[2]);
	
	Font_Info *info = font_info(prg);
	INFO_EXISTS(info->fonts, id)
	gfx::TTF *font = info->fonts[id];

	Image_Info *iinfo = image_info(prg);
	INFO_EXISTS(iinfo->images, image_id)
	gfx::Image *image = iinfo->images[image_id]->image;

	font->add_extra_glyph(glyph_id, image);

	return true;
}

// After defining the function, you just register them like this:
add_expression_handler("font_load", exprfunc_font_load);
add_instruction("font_destroy", fontfunc_destroy);
add_instruction("font_draw", fontfunc_draw);
add_expression_handler("font_width", exprfunc_font_width);
add_expression_handler("font_height", exprfunc_font_height);
add_instruction("font_add_extra_glyph", fontfunc_add_extra_glyph);