Mirai's Miscellaneous Misadventures

M43 / core / text.c

1/* license: AGPLv3 or later */
2/* copyright 2023 zamfofex */
3
4#include <mimimi.h>
5
6static unsigned char mimimi_paragraph_end(char ch)
7{
8	if (ch == 0) return 1;
9	if (ch == 0x0A || ch == 0x0B) return 1;
10	if (ch == 0x0C || ch == 0x0D) return 1;
11	return 0;
12}
13
14static unsigned char mimimi_space(char ch)
15{
16	if (mimimi_paragraph_end(ch)) return 1;
17	if (ch == 0x20 || ch == 0x09) return 1;
18	return 0;
19}
20
21int mimimi_measure_character(struct mimimi_font *font, char ch)
22{
23	int width;
24	int i;
25	int x, y;
26	
27	if (ch == 0x09) return 4;
28	if (ch == 0x20) return 4;
29	
30	i = ch - 0x20;
31	
32	width = 0;
33	for (x = 0 ; x < 8 ; x++)
34	for (y = 0 ; y < 16 ; y++)
35	{
36		if ((font->glyphs[i][y] >> (7 - x) & 1) != 0)
37			width = x + 1;
38	}
39	
40	return width + 1;
41}
42
43int mimimi_draw_character(struct mimimi_font *font, char ch, struct mimimi_image *target, int x0, int y0, unsigned char color)
44{
45	int width;
46	int x, y;
47	int x1, y1;
48	int i;
49	
50	width = mimimi_measure_character(font, ch);
51	i = ch - 0x20;
52	
53	for (x1 = 0 ; x1 < width ; x1++)
54	for (y1 = 0 ; y1 < 16 ; y1++)
55	{
56		x = x0 + x1;
57		y = y0 + y1;
58		
59		if (x < 0) continue;
60		if (y < 0) continue;
61		if (x >= target->width) continue;
62		if (y >= target->height) continue;
63		
64		if ((font->glyphs[i][y1] >> (7 - x1) & 1) == 0) continue;
65		
66		target->colors[x + y * target->width] = color;
67	}
68	
69	return x0 + width;
70}
71
72int mimimi_measure_segment(struct mimimi_font *font, char *text, int count)
73{
74	int x;
75	char ch;
76	
77	x = 0;
78	while (count-- > 0)
79	{
80		ch = *text++;
81		if (ch == 0) break;
82		x += mimimi_measure_character(font, ch);
83	}
84	
85	return x;
86}
87
88int mimimi_draw_segment(struct mimimi_font *font, char *text, int count, struct mimimi_image *target, int x, int y, unsigned char color)
89{
90	char ch;
91	
92	while (count-- > 0)
93	{
94		ch = *text++;
95		if (ch == 0) break;
96		x = mimimi_draw_character(font, ch, target, x, y, color);
97	}
98	
99	return x;
100}
101
102static char *mimimi_skip_nonspace(char *text)
103{
104	while (mimimi_space(*text) == 0) text++;
105	return text;
106}
107
108static char *mimimi_skip_space(char *text)
109{
110	while (mimimi_space(*text) != 0 && mimimi_paragraph_end(*text) == 0) text++;
111	return text;
112}
113
114static int mimimi_count_space(char *text)
115{
116	return mimimi_skip_space(text) - text;
117}
118
119static int mimimi_measure_space(struct mimimi_font *font, char *text)
120{
121	(void) font;
122	return 4 * mimimi_count_space(text);
123}
124
125char *mimimi_skip_word(char *text)
126{
127	text = mimimi_skip_nonspace(text);
128	text = mimimi_skip_space(text);
129	return text;
130}
131
132int mimimi_count_word(char *text)
133{
134	return mimimi_skip_nonspace(text) - text;
135}
136
137int mimimi_measure_word(struct mimimi_font *font, char *text)
138{
139	return mimimi_measure_segment(font, text, mimimi_count_word(text));
140}
141
142int mimimi_draw_word(struct mimimi_font *font, char *text, struct mimimi_image *target, int x, int y, unsigned char color)
143{
144	return mimimi_draw_segment(font, text, mimimi_count_word(text), target, x, y, color);
145}
146
147char *mimimi_skip_paragraph(char *text)
148{
149	while (mimimi_paragraph_end(*text) == 0) text++;
150	if (text[0] == '\r' && text[1] == '\n') text++;
151	if (text[0] != 0) text++;
152	return text;
153}
154
155int mimimi_count_paragraph(char *text)
156{
157	int n;
158	n = 0;
159	while (mimimi_paragraph_end(text[n]) == 0) n++;
160	return n;
161}
162
163int mimimi_measure_paragraph(struct mimimi_font *font, char *text)
164{
165	return mimimi_measure_segment(font, text, mimimi_count_paragraph(text));
166}
167
168int mimimi_draw_paragraph(struct mimimi_font *font, char *text, struct mimimi_image *target, int x, int y, unsigned char color)
169{
170	return mimimi_draw_segment(font, text, mimimi_count_paragraph(text), target, x, y, color);
171}
172
173static char *mimimi_skip_line_by_word(struct mimimi_font *font, char *text, int width)
174{
175	for (;;)
176	{
177		if (mimimi_paragraph_end(*text)) return text;
178		width -= mimimi_measure_word(font, text);
179		if (width < 0) return text;
180		text += mimimi_count_word(text);
181		width -= mimimi_measure_space(font, text);
182		text = mimimi_skip_word(text);
183	}
184}
185
186static char *mimimi_skip_line_by_character(struct mimimi_font *font, char *text, int width)
187{
188	for (;;)
189	{
190		if (mimimi_paragraph_end(*text)) return text;
191		width -= mimimi_measure_character(font, *text);
192		if (width < 0) return text;
193		text++;
194	}
195}
196
197int mimimi_count_line(struct mimimi_font *font, char *text0, int width)
198{
199	char *text;
200	
201	text = text0;
202	width++;
203	
204	if (mimimi_measure_segment(font, text, mimimi_count_word(text)) > width)
205		text = mimimi_skip_line_by_character(font, text, width);
206	else
207		text = mimimi_skip_line_by_word(font, text, width);
208	
209	text = mimimi_skip_space(text);
210	return text - text0;
211}
212
213char *mimimi_skip_line(struct mimimi_font *font, char *text, int width)
214{
215	text += mimimi_count_line(font, text, width);
216	while (mimimi_paragraph_end(*text) != 0 && *text != 0) text++;
217	return text;
218}
219
220int mimimi_measure_line(struct mimimi_font *font, char *text, int width)
221{
222	return mimimi_measure_segment(font, text, mimimi_count_line(font, text, width));
223}
224
225int mimimi_draw_line(struct mimimi_font *font, char *text, int width, struct mimimi_image *target, int x, int y, unsigned char color)
226{
227	return mimimi_draw_segment(font, text, mimimi_count_line(font, text, width), target, x, y, color);
228}
229
230int mimimi_measure_text(struct mimimi_font *font, char *text, int width, int line_height)
231{
232	int y;
233	
234	y = 0;
235	while (*text != 0)
236	{
237		text = mimimi_skip_line(font, text, width);
238		y += line_height;
239	}
240	
241	return y;
242}
243
244int 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)
245{
246	while (*text != 0)
247	{
248		mimimi_draw_line(font, text, width, target, x, y, color);
249		text = mimimi_skip_line(font, text, width);
250		y += line_height;
251	}
252	
253	return y;
254}