Mirai's Miscellaneous Misadventures

M48 / core / text.c

/* license: AGPLv3 or later */
/* copyright 2023 zamfofex */

#include <mimimi.h>

static unsigned char mimimi_paragraph_end(char ch)
{
	if (ch == 0) return 1;
	if (ch == 0x0A || ch == 0x0B) return 1;
	if (ch == 0x0C || ch == 0x0D) return 1;
	return 0;
}

static unsigned char mimimi_space(char ch)
{
	if (mimimi_paragraph_end(ch)) return 1;
	if (ch == 0x20 || ch == 0x09) return 1;
	return 0;
}

int mimimi_measure_character(struct mimimi_font *font, char ch)
{
	int width;
	int i;
	int x, y;
	
	if (ch == 0x09) return 4;
	if (ch == 0x20) return 4;
	
	i = ch - 0x20;
	
	width = 0;
	for (x = 0 ; x < 8 ; x++)
	for (y = 0 ; y < 16 ; y++)
	{
		if ((font->glyphs[i][y] >> (7 - x) & 1) != 0)
			width = x + 1;
	}
	
	return width + 1;
}

int mimimi_draw_character(struct mimimi_font *font, char ch, struct mimimi_image *target, int x0, int y0, unsigned char color)
{
	int width;
	int x, y;
	int x1, y1;
	int i;
	
	width = mimimi_measure_character(font, ch);
	i = ch - 0x20;
	
	for (x1 = 0 ; x1 < width ; x1++)
	for (y1 = 0 ; y1 < 16 ; y1++)
	{
		x = x0 + x1;
		y = y0 + y1;
		
		if (x < 0) continue;
		if (y < 0) continue;
		if (x >= target->width) continue;
		if (y >= target->height) continue;
		
		if ((font->glyphs[i][y1] >> (7 - x1) & 1) == 0) continue;
		
		target->colors[x + y * target->width] = color;
	}
	
	return x0 + width;
}

int mimimi_measure_segment(struct mimimi_font *font, char *text, int count)
{
	int x;
	char ch;
	
	x = 0;
	while (count-- > 0)
	{
		ch = *text++;
		if (ch == 0) break;
		x += mimimi_measure_character(font, ch);
	}
	
	return x;
}

int mimimi_draw_segment(struct mimimi_font *font, char *text, int count, struct mimimi_image *target, int x, int y, unsigned char color)
{
	char ch;
	
	while (count-- > 0)
	{
		ch = *text++;
		if (ch == 0) break;
		x = mimimi_draw_character(font, ch, target, x, y, color);
	}
	
	return x;
}

static char *mimimi_skip_nonspace(char *text)
{
	while (mimimi_space(*text) == 0) text++;
	return text;
}

static char *mimimi_skip_space(char *text)
{
	while (mimimi_space(*text) != 0 && mimimi_paragraph_end(*text) == 0) text++;
	return text;
}

static int mimimi_count_space(char *text)
{
	return mimimi_skip_space(text) - text;
}

static int mimimi_measure_space(struct mimimi_font *font, char *text)
{
	(void) font;
	return 4 * mimimi_count_space(text);
}

char *mimimi_skip_word(char *text)
{
	text = mimimi_skip_nonspace(text);
	text = mimimi_skip_space(text);
	return text;
}

int mimimi_count_word(char *text)
{
	return mimimi_skip_nonspace(text) - text;
}

int mimimi_measure_word(struct mimimi_font *font, char *text)
{
	return mimimi_measure_segment(font, text, mimimi_count_word(text));
}

int mimimi_draw_word(struct mimimi_font *font, char *text, struct mimimi_image *target, int x, int y, unsigned char color)
{
	return mimimi_draw_segment(font, text, mimimi_count_word(text), target, x, y, color);
}

char *mimimi_skip_paragraph(char *text)
{
	while (mimimi_paragraph_end(*text) == 0) text++;
	if (text[0] == '\r' && text[1] == '\n') text++;
	if (text[0] != 0) text++;
	return text;
}

int mimimi_count_paragraph(char *text)
{
	int n;
	n = 0;
	while (mimimi_paragraph_end(text[n]) == 0) n++;
	return n;
}

int mimimi_measure_paragraph(struct mimimi_font *font, char *text)
{
	return mimimi_measure_segment(font, text, mimimi_count_paragraph(text));
}

int mimimi_draw_paragraph(struct mimimi_font *font, char *text, struct mimimi_image *target, int x, int y, unsigned char color)
{
	return mimimi_draw_segment(font, text, mimimi_count_paragraph(text), target, x, y, color);
}

static char *mimimi_skip_line_by_word(struct mimimi_font *font, char *text, int width)
{
	for (;;)
	{
		if (mimimi_paragraph_end(*text)) return text;
		width -= mimimi_measure_word(font, text);
		if (width < 0) return text;
		text += mimimi_count_word(text);
		width -= mimimi_measure_space(font, text);
		text = mimimi_skip_word(text);
	}
}

static char *mimimi_skip_line_by_character(struct mimimi_font *font, char *text, int width)
{
	for (;;)
	{
		if (mimimi_paragraph_end(*text)) return text;
		width -= mimimi_measure_character(font, *text);
		if (width < 0) return text;
		text++;
	}
}

int mimimi_count_line(struct mimimi_font *font, char *text0, int width)
{
	char *text;
	
	text = text0;
	width++;
	
	if (mimimi_measure_segment(font, text, mimimi_count_word(text)) > width)
		text = mimimi_skip_line_by_character(font, text, width);
	else
		text = mimimi_skip_line_by_word(font, text, width);
	
	text = mimimi_skip_space(text);
	return text - text0;
}

char *mimimi_skip_line(struct mimimi_font *font, char *text, int width)
{
	text += mimimi_count_line(font, text, width);
	while (mimimi_paragraph_end(*text) != 0 && *text != 0) text++;
	return text;
}

int mimimi_measure_line(struct mimimi_font *font, char *text, int width)
{
	return mimimi_measure_segment(font, text, mimimi_count_line(font, text, width));
}

int mimimi_draw_line(struct mimimi_font *font, char *text, int width, struct mimimi_image *target, int x, int y, unsigned char color)
{
	return mimimi_draw_segment(font, text, mimimi_count_line(font, text, width), target, x, y, color);
}

int mimimi_measure_text(struct mimimi_font *font, char *text, int width, int line_height)
{
	int y;
	
	y = 0;
	while (*text != 0)
	{
		text = mimimi_skip_line(font, text, width);
		y += line_height;
	}
	
	return y;
}

int mimimi_draw_text(struct mimimi_font *font, char *text, int width, int line_height, struct mimimi_image *target, int x, int y, unsigned char color)
{
	while (*text != 0)
	{
		mimimi_draw_line(font, text, width, target, x, y, color);
		text = mimimi_skip_line(font, text, width);
		y += line_height;
	}
	
	return y;
}