Mirai's Miscellaneous Misadventures
M53 / core / text.c
1
2
3
4#include "../mimimi.h"
5
6static unsigned char mimimi_paragraph_end(char ch)
7{
8 if (ch == 0)
9 return 1;
10 if (ch == 0x0A || ch == 0x0B)
11 return 1;
12 if (ch == 0x0C || ch == 0x0D)
13 return 1;
14 return 0;
15}
16
17static unsigned char mimimi_space(char ch)
18{
19 if (mimimi_paragraph_end(ch))
20 return 1;
21 if (ch == 0x20 || ch == 0x09)
22 return 1;
23 return 0;
24}
25
26int mimimi_measure_character(struct mimimi_font *font, char ch)
27{
28 int width;
29 int i;
30 int x, y;
31
32 if (ch == 0x09)
33 return 4;
34 if (ch == 0x20)
35 return 4;
36
37 i = ch - 0x20;
38
39 width = 0;
40 for (x = 0; x < 8; x++)
41 for (y = 0; y < 16; y++)
42 if ((font->glyphs[i][y] >> (7 - x) & 1) != 0)
43 width = x + 1;
44
45 return width + 1;
46}
47
48int mimimi_draw_character(struct mimimi_font *font, char ch,
49 struct mimimi_image *target, int x0, int y0, unsigned char color)
50{
51 int width;
52 int x, y;
53 int x1, y1;
54 int i;
55
56 width = mimimi_measure_character(font, ch);
57 i = ch - 0x20;
58
59 for (x1 = 0; x1 < width; x1++)
60 for (y1 = 0; y1 < 16; y1++) {
61 x = x0 + x1;
62 y = y0 + y1;
63
64 if (x < 0)
65 continue;
66 if (y < 0)
67 continue;
68 if (x >= target->width)
69 continue;
70 if (y >= target->height)
71 continue;
72
73 if ((font->glyphs[i][y1] >> (7 - x1) & 1) == 0)
74 continue;
75
76 target->colors[x + y * target->width] = color;
77 }
78
79 return x0 + width;
80}
81
82static int mimimi_kern(struct mimimi_font *font, char ch1, char ch2)
83{
84 int width;
85 int widths[16];
86 int i, j;
87 int x, y;
88
89 if (ch1 == 0x19 || ch1 == 0x20)
90 return 4;
91 if (ch2 == 0x19 || ch2 == 0x20 || ch2 == 0)
92 return mimimi_measure_character(font, ch1);
93
94 i = ch1 - 0x20;
95 j = ch2 - 0x20;
96
97 for (y = 0; y < 16; y++) {
98 widths[y] = 0;
99 for (x = 0; x < 8; x++)
100 if ((font->glyphs[i][y] >> (7 - x) & 1) != 0)
101 if (x + 1 > widths[y])
102 widths[y] = x + 1;
103 }
104
105 for (y = 0; y < 16; y++) {
106 for (x = 0; x < 8; x++) {
107 if ((font->glyphs[j][y] >> (7 - x) & 1) != 0)
108 break;
109 if (y > 0 && (font->glyphs[j][y - 1] >> (7 - x) & 1) != 0)
110 break;
111 if (y < 15 && (font->glyphs[j][y + 1] >> (7 - x) & 1) != 0)
112 break;
113 }
114 widths[y] -= x;
115 }
116
117 width = 0;
118 for (y = 0; y < 16; y++)
119 if (widths[y] > width)
120 width = widths[y];
121
122 return width + 1;
123}
124
125int mimimi_measure_segment(struct mimimi_font *font, char *text, int count)
126{
127 int x;
128 char ch;
129
130 x = 0;
131 while (count-- > 0) {
132 ch = *text++;
133 if (ch == 0)
134 break;
135 x += mimimi_kern(font, ch, *text);
136 }
137
138 return x;
139}
140
141int mimimi_draw_segment(struct mimimi_font *font, char *text, int count,
142 struct mimimi_image *target, int x, int y, unsigned char color)
143{
144 char ch;
145
146 while (count-- > 0) {
147 ch = *text++;
148 if (ch == 0)
149 break;
150 mimimi_draw_character(font, ch, target, x, y, color);
151 x += mimimi_kern(font, ch, *text);
152 }
153
154 return x;
155}
156
157static char *mimimi_skip_nonspace(char *text)
158{
159 while (mimimi_space(*text) == 0)
160 text++;
161 return text;
162}
163
164static char *mimimi_skip_space(char *text)
165{
166 while (mimimi_space(*text) != 0 && mimimi_paragraph_end(*text) == 0)
167 text++;
168 return text;
169}
170
171static int mimimi_count_space(char *text)
172{
173 return mimimi_skip_space(text) - text;
174}
175
176static int mimimi_measure_space(struct mimimi_font *font, char *text)
177{
178 (void) font;
179 return 4 * mimimi_count_space(text);
180}
181
182char *mimimi_skip_word(char *text)
183{
184 text = mimimi_skip_nonspace(text);
185 text = mimimi_skip_space(text);
186 return text;
187}
188
189int mimimi_count_word(char *text)
190{
191 return mimimi_skip_nonspace(text) - text;
192}
193
194int mimimi_measure_word(struct mimimi_font *font, char *text)
195{
196 return mimimi_measure_segment(font, text, mimimi_count_word(text));
197}
198
199int mimimi_draw_word(struct mimimi_font *font, char *text,
200 struct mimimi_image *target, int x, int y, unsigned char color)
201{
202 return mimimi_draw_segment(font, text, mimimi_count_word(text), target,
203 x, y, color);
204}
205
206char *mimimi_skip_paragraph(char *text)
207{
208 while (mimimi_paragraph_end(*text) == 0)
209 text++;
210 if (text[0] == '\r' && text[1] == '\n')
211 text++;
212 if (text[0] != 0)
213 text++;
214 return text;
215}
216
217int mimimi_count_paragraph(char *text)
218{
219 int n;
220 n = 0;
221 while (mimimi_paragraph_end(text[n]) == 0)
222 n++;
223 return n;
224}
225
226int mimimi_measure_paragraph(struct mimimi_font *font, char *text)
227{
228 return mimimi_measure_segment(font, text,
229 mimimi_count_paragraph(text));
230}
231
232int mimimi_draw_paragraph(struct mimimi_font *font, char *text,
233 struct mimimi_image *target, int x, int y, unsigned char color)
234{
235 return mimimi_draw_segment(font, text, mimimi_count_paragraph(text),
236 target, x, y, color);
237}
238
239static char *mimimi_skip_line_by_word(struct mimimi_font *font, char *text,
240 int width)
241{
242 for (;;) {
243 if (mimimi_paragraph_end(*text))
244 return text;
245 width -= mimimi_measure_word(font, text);
246 if (width < 0)
247 return text;
248 text += mimimi_count_word(text);
249 width -= mimimi_measure_space(font, text);
250 text = mimimi_skip_word(text);
251 }
252}
253
254static char *mimimi_skip_line_by_character(struct mimimi_font *font,
255 char *text, int width)
256{
257 for (;;) {
258 if (mimimi_paragraph_end(*text))
259 return text;
260 width -= mimimi_measure_character(font, *text);
261 if (width < 0)
262 return text;
263 text++;
264 }
265}
266
267int mimimi_count_line(struct mimimi_font *font, char *text0, int width)
268{
269 char *text;
270
271 text = text0;
272 width++;
273
274 if (mimimi_measure_segment(font, text,
275 mimimi_count_word(text)) > width)
276 text = mimimi_skip_line_by_character(font, text, width);
277 else
278 text = mimimi_skip_line_by_word(font, text, width);
279
280 text = mimimi_skip_space(text);
281 return text - text0;
282}
283
284char *mimimi_skip_line(struct mimimi_font *font, char *text, int width)
285{
286 text += mimimi_count_line(font, text, width);
287 while (mimimi_paragraph_end(*text) != 0 && *text != 0)
288 text++;
289 return text;
290}
291
292int mimimi_measure_line(struct mimimi_font *font, char *text, int width)
293{
294 int count;
295 count = mimimi_count_line(font, text, width);
296 return mimimi_measure_segment(font, text, count);
297}
298
299int mimimi_draw_line(struct mimimi_font *font, char *text, int width,
300 struct mimimi_image *target, int x, int y, unsigned char color)
301{
302 int count;
303 count = mimimi_count_line(font, text, width);
304 return mimimi_draw_segment(font, text, count, target, x, y, color);
305}
306
307int mimimi_measure_text(struct mimimi_font *font, char *text, int width,
308 int line_height)
309{
310 int y;
311
312 y = 0;
313 while (*text != 0) {
314 text = mimimi_skip_line(font, text, width);
315 y += line_height;
316 }
317
318 return y;
319}
320
321int mimimi_draw_text(struct mimimi_font *font, char *text, int width,
322 int line_height, struct mimimi_image *target, int x, int y,
323 unsigned char color)
324{
325 while (*text != 0) {
326 mimimi_draw_line(font, text, width, target, x, y, color);
327 text = mimimi_skip_line(font, text, width);
328 y += line_height;
329 }
330
331 return y;
332}