Alchemy
Loading...
Searching...
No Matches

glyphs.c

Go to the documentation of this file.
1/// @file
2/// Characters rendered into tiles, string widths and number formatting.
3/// Part of window.c, the window object, compiled only through it.
4
6
7// UiText_RenderGlyphPair draws its glyphs into a buffer of one byte per pixel
8// (Iwram_ExpandBitRuns writes a glyph's rows there in a colour), in rows 24
9// bytes apart, then packs it into 4bpp tiles.
10
11#if (LANGUAGE != LANGUAGE_JAPANESE)
12/// Draws a character, and a second one when the code carries it in bits 8 to
13/// 15, into a 16x16-pixel cell of four 4bpp tiles at out: in the text colour
14/// over a shadow, or with an outline when UiRenderWork.outline is 1. Returns
15/// the width of the text drawn in pixels.
16/// The caller supplies 32 words for four tiles.
18 u8 pixels[384];
19 struct UiRenderWork *work;
20 const u8 *glyph;
21 s32 width;
22 s32 colour;
23 s32 shadowColour;
24 s32 firstIndex;
25 s32 secondIndex;
26 u16 secondWidth;
27 u8 *pixel;
28 s32 tileColumn;
29 s32 tileRow;
30 s32 line;
31 s32 pixelsLeft;
32 u32 tileLine;
33
34 work = UI_WORK;
35 secondIndex = (code << 8) >> 16;
36 code &= 255;
37 Iwram_ClearWords(pixels, 384);
38 // While UiRenderWork.mode is set, the text is colour 8 with no shadow.
39 if (work->mode != 0) {
40 shadowColour = 0;
41 colour = 8;
42 } else {
43 shadowColour = 1;
44 colour = work->colour;
45 }
46 firstIndex = code - 32;
47 glyph = firstIndex * sizeof(struct FontGlyph) + (const u8 *)gUiText_Glyphs;
48 width = ((const struct FontGlyph *)glyph)->width;
49 glyph = (const u8 *)((const struct FontGlyph *)glyph)->rows;
50 if (work->outline == 1) {
51 Iwram_ExpandBitRuns(glyph, pixels + 49, shadowColour);
52 Iwram_ExpandBitRuns(glyph, pixels + 50, shadowColour);
53 Iwram_ExpandBitRuns(glyph, pixels + 32, colour);
54 Iwram_ExpandBitRuns(glyph, pixels + 33, colour);
55 width++;
56 } else {
57 Iwram_ExpandBitRuns(glyph, pixels + 49, shadowColour);
58 Iwram_ExpandBitRuns(glyph, pixels + 32, colour);
59 }
60 // The second character follows the first.
61 if ((u16)secondIndex != 0) {
62#ifdef UBFIX
63 // Form only the actual glyph address: &glyphs[-32] is already outside
64 // the array before the later byte offset is added. The direct index
65 // changes native instruction selection (EN: text grows by 8 bytes).
66 glyph = (const u8 *)&gUiText_Glyphs[(u16)secondIndex - 32];
67#else
68 glyph = (const u8 *)&gUiText_Glyphs[-32] + ((u16)secondIndex << 5);
69#endif
70 secondWidth = *(const u16 *)glyph;
71 glyph += 2;
72 if (work->outline == 1) {
73 u8 *dst = pixels + width;
74 Iwram_ExpandBitRuns(glyph, dst + 49, shadowColour);
75 Iwram_ExpandBitRuns(glyph, dst + 50, shadowColour);
76 Iwram_ExpandBitRuns(glyph, dst + 32, colour);
77 Iwram_ExpandBitRuns(glyph, dst + 33, colour);
78 secondWidth += 1;
79 } else {
80 u8 *dst = pixels + width;
81 u8 *p;
82 p = dst + 49;
83 Iwram_ExpandBitRuns(glyph, p, shadowColour);
84 p = dst + 32;
85 Iwram_ExpandBitRuns(glyph, p, colour);
86 }
87 width += secondWidth;
88 }
89
90#else
91/// Draws a character into a 16x16-pixel cell of four 4bpp tiles at out: in the
92/// text colour over a shadow, or with an outline when UiRenderWork.outline is
93/// 1, with the kana mark in the code's top two bits above its top right.
94/// Codes from 256 are kanji. Returns the character's width in pixels.
95/// The caller supplies 32 words for four tiles.
97 u8 pixels[256];
98 struct UiRenderWork *work;
99 const u8 *glyph;
100 const u8 *markGlyph;
101 s32 width;
102 s32 colour;
103 s32 shadowColour;
104 u32 markCode;
105 u8 *pixel;
106 s32 tileColumn;
107 s32 tileRow;
108 s32 line;
109 s32 pixelsLeft;
110 u32 tileLine;
111
112 /* FAKEMATCH(one-pass): an empty block keeps the spill of out ahead of the
113 * work-address load; as no block, 2 of 185 instructions differ in tbs-ja,
114 * the only edition with this body. */
115 do {
116 } while (0);
117 work = UI_WORK;
118 markGlyph = 0;
120 if (markCode != 0)
121 markGlyph =
122 (const u8 *)((const struct FontGlyph *)((const u8 *)gUiText_Glyphs +
123 (markCode - 32) *
124 sizeof(struct FontGlyph)))
125 ->rows;
126 code &= (1 << TEXT_CODE_MARK_SHIFT) - 1;
127 if (code <= 0xff) {
128 glyph = (const u8 *)gUiText_Glyphs + (code - 32) * sizeof(struct FontGlyph);
129 width = ((const struct FontGlyph *)glyph)->width;
130 glyph = (const u8 *)((const struct FontGlyph *)glyph)->rows;
131 } else {
132 glyph = gUiText_KanjiGlyphs + (code - 256) * 24;
133 width = 10;
134 }
135 Iwram_ClearWords(pixels, 256);
136 if (work->mode != 0) {
137 shadowColour = 0;
138 colour = 8;
139 } else {
140 shadowColour = 1;
141 colour = work->colour;
142 }
143 if (work->outline == 1) {
144 Iwram_ExpandBitRuns(glyph, pixels + 49, shadowColour);
145 Iwram_ExpandBitRuns(glyph, pixels + 50, shadowColour);
146 if (markGlyph != 0) {
147 Iwram_ExpandBitRuns(markGlyph, pixels + 24, shadowColour);
148 Iwram_ExpandBitRuns(markGlyph, pixels + 25, shadowColour);
149 }
150 Iwram_ExpandBitRuns(glyph, pixels + 32, colour);
151 Iwram_ExpandBitRuns(glyph, pixels + 33, colour);
152 if (markGlyph != 0) {
153 /* FAKEMATCH(temporary): pixel assigned in the argument computes pixels
154 * + 7 in r1 and copies it to r5, as native; as a plain pixels + 7
155 * argument, 4 of 185 instructions differ in tbs-ja. */
156 Iwram_ExpandBitRuns(markGlyph, pixel = pixels + 7, colour);
157 Iwram_ExpandBitRuns(markGlyph, pixels + 8, colour);
158 }
159 width++;
160 } else {
161 Iwram_ExpandBitRuns(glyph, pixels + 49, shadowColour);
162 if (markGlyph != 0)
163 Iwram_ExpandBitRuns(markGlyph, pixels + 24, shadowColour);
164 Iwram_ExpandBitRuns(glyph, pixels + 32, colour);
165 if (markGlyph != 0) {
166 /* FAKEMATCH(temporary): pixel assigned in the argument, as in the
167 * outlined path above; as a plain pixels + 7 argument, 4 of 185
168 * instructions differ in tbs-ja. */
169 Iwram_ExpandBitRuns(markGlyph, pixel = pixels + 7, colour);
170 }
171 }
172#endif
173
174 // Pack either font into four tiles, with the leftmost pixel in the low
175 // nibble.
176 pixel = pixels + 7;
177 tileColumn = 0;
178 do {
179 tileRow = 0;
180 do {
181 line = 0;
182 do {
183 tileLine = 0;
184 pixelsLeft = 7;
185 do {
186 tileLine = (tileLine << 4) + *pixel--;
187 pixelsLeft--;
188 } while (pixelsLeft >= 0);
189 *out++ = tileLine;
190 line++;
191 pixel += 24;
192 } while (line <= 7);
193 tileRow++;
194 pixel -= 120;
195 } while (tileRow <= 1);
196 tileColumn++;
197 pixel += 112;
198 } while (tileColumn <= 1);
199 return width;
200}
201
202// The German, Spanish, French and Italian editions count every character up
203// to 0xff as 10 pixels, and those above as nothing.
204#if (LANGUAGE == LANGUAGE_GERMAN || LANGUAGE == LANGUAGE_SPANISH || \
205 LANGUAGE == LANGUAGE_FRENCH || LANGUAGE == LANGUAGE_ITALIAN)
206#define WIDE_WIDTH_FIXED 1
207#endif
208
209/// The main font's glyph n, counted from the space character.
210#define FONT_GLYPH(n) \
211 ((const struct FontGlyph *)((n) * sizeof(struct FontGlyph) + \
212 (const u8 *)gUiText_Glyphs))
213
214/// Returns the width in pixels of a zero-terminated string of 16-bit character
215/// codes: 4 for a space, the font width for other codes up to 0xff (in German,
216/// Spanish, French and Italian a flat 10) and 10 for a kanji. The kana marks
217/// take no width.
219 s32 width;
220 u16 *cursor;
221 u32 code;
222#if !defined(WIDE_WIDTH_FIXED)
223 u32 glyphIndex;
224#endif
225
226 code = *text;
227 width = 0;
228 cursor = text + 1;
229 if (code != 0) {
230 do {
231 if (code == 0x20) {
232 width += 4;
233 } else if (code <= 0xffU) {
234#if defined(WIDE_WIDTH_FIXED)
235 width += 10;
236#else
237 glyphIndex = code - TEXT_VOICED_MARK;
238 if (glyphIndex > 1U) {
239 // The font starts at the space.
240 glyphIndex += TEXT_VOICED_MARK - TEXT_SPACE;
241 width += FONT_GLYPH(glyphIndex)->width;
242 }
243 } else {
244 width += 10;
245#endif
246 }
247 code = *cursor;
248 cursor += 1;
249 } while (code != 0);
250 }
251 return width;
252}
253
254/// Draws a zero-terminated string of 16-bit character codes into a text canvas
255/// window at pixel (x, y), running its colour, outline, line spacing and new
256/// line codes; other control codes are skipped with their arguments. A NULL
257/// text draws the decoded text in UiRenderWork.entries.
258void UiText_RenderWideStringAtOffset(u16 *text, struct UiWindow *window, s32 x,
259 s32 y) {
260 u8 *base;
261 struct UiRenderWork *work;
262 u32 code;
263#if (LANGUAGE != LANGUAGE_JAPANESE)
264 u32 nextCode;
265#endif
266 s16 lineStartX;
267
268 base = gWindowWork[0];
269 work = (struct UiRenderWork *)base;
270 code = 0;
271 lineStartX = x;
272 if (text == NULL) {
273 text = work->entries;
274 work->entries[work->count] = code;
275 work->count = (work->count + 1) & RENDER_ENTRY_MASK;
276 }
277#if (LANGUAGE != LANGUAGE_JAPANESE)
278 for (;;)
279#else
280 while ((code = *text++) != 0)
281#endif
282 {
283#if (LANGUAGE != LANGUAGE_JAPANESE)
284 code = *text++;
285 if (code > 0xff)
286 code = 0x40;
287 if (code == 0)
288 break;
289#endif
290 if (code <= TEXT_END_ALT) {
291 switch (code) {
292 case TEXT_COLOUR:
293 work->colour = *text;
294 text++;
295 break;
296 case TEXT_OUTLINE:
297 work->outline = *text;
298 text++;
299 break;
301 work->lineSpacing = *text;
302 text++;
303 break;
306 break;
307 case TEXT_NEWLINE:
308 x = lineStartX;
309 y += 15;
310 break;
311 case 14:
312 case 15:
313 case 28:
314 text++;
315 // Skip the second operand too.
316 // Fall through.
317 case 11:
318 case 12:
319 case 17:
320#if (LANGUAGE != LANGUAGE_JAPANESE)
321 case 29:
322#endif
323 text++;
324 break;
325 }
326 } else {
327#if (LANGUAGE != LANGUAGE_JAPANESE)
328 // Pair two narrow characters into one cell, as UiWork_StepChannelScript
329 // does.
330 if ((window->flags & UI_WINDOW_TEXT_CANVAS) == 0) {
331 nextCode = *text;
332#if (LANGUAGE == LANGUAGE_SPANISH)
333 if (code > 32 && nextCode > 32) {
334 s16 width = gUiText_Glyphs[code - 32].width +
335 gUiText_Glyphs[nextCode - 32].width;
336
337 if (work->outline == 1) {
338 if ((u16)width <= 14) {
339 code |= nextCode << 8;
340 text++;
341 }
342 } else if ((u16)width <= 15) {
343 code |= nextCode << 8;
344 text++;
345 }
346 }
347#else
348 if (code > 32 && nextCode > 32 &&
349 (u16)(gUiText_Glyphs[code - 32].width +
350 gUiText_Glyphs[nextCode - 32].width) <= 15) {
351 code |= nextCode << 8;
352 text++;
353 }
354#endif
355 }
356#else
357 if (*text == TEXT_VOICED_MARK) {
358 code |= TEXT_CODE_VOICED;
359 text++;
360 } else if (*text == TEXT_SEMIVOICED_MARK) {
361 code |= TEXT_CODE_SEMIVOICED;
362 text++;
363 }
364#endif
365 x += UiText_DrawGlyph(window, code, x, y, 0);
366 }
367 }
368}
369
370/// Draws a string of 16-bit character codes straight into the UI tilemap, as
371/// tiles, inside a window at tile (offsetX, offsetY) of its interior, writing
372/// both the work block's copy and VRAM. A NULL buffer draws the decoded text
373/// in UiRenderWork.entries.
374/// Nothing calls it.
376 const struct UiWindow *work,
377 s32 offsetX, s32 offsetY) {
378 struct UiRenderWork *canvas = UI_WORK;
379 u32 cell;
380
381 if (buffer == NULL) {
382 u16 *counter = &canvas->count;
383
384 buffer = canvas->entries;
385 canvas->entries[*counter] = 0;
386 *counter = (*counter + 1) & RENDER_ENTRY_MASK;
387 }
388
389 cell = ((work->y + offsetY + 1) << 5) + (work->x + offsetX) + 1;
390 if (cell < 32 * 20) {
391 // Inside the tilemap.
392 s32 src;
393 s32 dst;
394
395 cell *= 2;
396 dst = (s32)UI_TILEMAP_VRAM + cell;
397 src = (s32)canvas->tilemap + cell;
398
399 UiText_RenderStringTiles(buffer, (u16 *)src, (u16 *)dst,
401 }
402}
403
404/// Draws a zero-terminated string of 16-bit character codes into a window's
405/// tilemap at tile (x, y) of its interior, one tile per character, skipping
406/// control codes; a NULL text draws the decoded text in UiRenderWork.entries.
407/// Control operands are skipped, not rendered as glyphs; the input is read
408/// only.
409void UiText_RenderWideStringInWindow(s16 *text, struct UiWindow *window, s32 x,
410 s32 y) {
411 struct UiRenderWork *work;
412 u16 code;
413 s16 lineStartX;
414
415 work = UI_WORK;
416 lineStartX = x;
417 if (text == NULL) {
418 text = work->entries;
419 work->entries[work->count] = 0;
420 work->count = (work->count + 1) & RENDER_ENTRY_MASK;
421 }
422 code = *text++;
423 if (code != 0)
424 do {
425 if (code <= TEXT_END_ALT) {
426 switch (code) {
427 case TEXT_NEWLINE:
428 x = lineStartX;
429 y++;
430 break;
431 case 14:
432 case 15:
433 case 28:
434 text++;
435 // Skip the second operand too.
436 // Fall through.
437 case 7:
438 case 8:
439 case 9:
440 case 10:
441 case 11:
442 case 12:
443 case 17:
444#if (LANGUAGE != LANGUAGE_JAPANESE)
445 case 29:
446#endif
447 text++;
448 break;
449 }
450 } else {
451 UiWindow_PutGlyph(window, code, x, y, 0);
452#if (LANGUAGE == LANGUAGE_GERMAN) || (LANGUAGE == LANGUAGE_SPANISH) || \
453 (LANGUAGE == LANGUAGE_FRENCH) || (LANGUAGE == LANGUAGE_ITALIAN)
454 x++;
455#else
456 // The kana marks share a tile.
457 if ((u16)(code - TEXT_VOICED_MARK) > 1)
458 x++;
459#endif
460 }
461 code = *text++;
462 } while (code != 0);
463 work->dirty = 1;
464}
465
466/// Writes value as decimal text into buffer (14 bytes) and returns where the
467/// text starts. With width 0 the number has no padding and a minus sign when
468/// negative; otherwise it is right-aligned in width characters (up to 12) and
469/// unsigned.
470u8 *UiText_FormatNumber(u8 *buffer, s32 input, s32 width) {
471 s32 offset;
472 s32 value;
473 s32 negative;
474 s32 spaceCharacter;
475 s32 minusCharacter;
476 u8 *leading;
477 u8 *trim;
478
479 value = input;
480 negative = 0;
481 if (value < 0) {
482 if (width == 0)
483 negative = 1;
484 value = 0U - value;
485 }
486
487 // Twelve digits, then spaces for the leading zeros and the sign in front.
488 buffer[0] = ' ';
489 for (offset = 12; offset != 0; offset--) {
490 buffer[offset] = value % 10 + '0';
491 value = value / 10;
492 }
493
494 offset = 0;
495 buffer[13] = offset;
496 spaceCharacter = ' ';
497 offset = 1;
498 minusCharacter = '-';
499 for (leading = buffer; offset != 13; leading++, offset++) {
500 if (leading[1] == '0') {
501 if (offset != 12)
502 leading[1] = spaceCharacter;
503 } else {
504 if (negative != 0)
505 leading[0] = minusCharacter;
506 break;
507 }
508 }
509
510 if (width == 0) {
511 offset = 0;
512 if (buffer[0] == ' ') {
513 trim = buffer;
514 do {
515 offset++;
516 if (offset == 12)
517 break;
518 trim++;
519 } while (*trim == ' ');
520 }
521 return buffer + offset;
522 }
523
524 if (width < 0 || width > 12)
525 width = 12;
526 return buffer + 13 - width;
527}
const u16 gUiText_MarkGlyphCodes[]
void UiWork_ResetCounters(void)
Resets the text style glyphs are drawn with: colour 15, no outline, line spacing 10.
Definition frames.c:236
const struct FontGlyph gUiText_Glyphs[]
#define FONT_GLYPH(n)
The main font's glyph n, counted from the space character.
Definition glyphs.c:210
u8 * UiText_FormatNumber(u8 *buffer, s32 input, s32 width)
Writes value as decimal text into buffer (14 bytes) and returns where the text starts.
Definition glyphs.c:470
s32 UiText_GetWideStringWidth(u16 *text)
Returns the width in pixels of a zero-terminated string of 16-bit character codes: 4 for a space,...
Definition glyphs.c:218
s32 UiText_RenderGlyphPair(s32 code, u32 *out)
Draws a character, and a second one when the code carries it in bits 8 to 15, into a 16x16-pixel cell...
Definition glyphs.c:17
void UiText_RenderWideStringInWindow(s16 *text, struct UiWindow *window, s32 x, s32 y)
Draws a zero-terminated string of 16-bit character codes into a window's tilemap at tile (x,...
Definition glyphs.c:409
UNUSED void UiText_RenderGlyphTileAtWorkOffset(u16 *buffer, const struct UiWindow *work, s32 offsetX, s32 offsetY)
Draws a string of 16-bit character codes straight into the UI tilemap, as tiles, inside a window at t...
Definition glyphs.c:375
void UiText_RenderWideStringAtOffset(u16 *text, struct UiWindow *window, s32 x, s32 y)
Draws a zero-terminated string of 16-bit character codes into a text canvas window at pixel (x,...
Definition glyphs.c:258
#define Iwram_ExpandBitRuns
Definition iwram_call.h:27
static s32 Iwram_ClearWords(void *destination, s32 size)
Definition iwram_call.h:55
#define NULL
Definition bilibin.h:6
u8 gWindowWork[]
A character of the text font: its width and its rows of pixels.
Definition glyph.h:28
u16 width
pixels
Definition glyph.h:29
u16 rows[FONT_GLYPH_ROWS]
Definition glyph.h:30
The window system's work: the windows' tilemap, the windows, the three text channels,...
Definition window.h:19
u8 mode
Set while Mind Read shows thoughts: round frame corners, colour 8 text with no shadow,...
Definition window.h:35
u16 tilemap[640]
the windows' BG tilemap, 32 by 20 tiles
Definition window.h:20
u8 dirty
The tilemap's 4-row bands to upload: bit 0 for all, bit n + 1 for band n.
Definition window.h:32
u16 entries[RENDER_ENTRY_MASK+1]
decoded text, a ring of codes
Definition window.h:46
u16 count
where the next code goes in entries
Definition window.h:48
u16 colour
the current channel's, copied in to draw
Definition window.h:45
u16 outline
the current channel's, copied in to draw
Definition window.h:44
u16 lineSpacing
the current channel's, copied in to draw
Definition window.h:42
A window: a framed rectangle of the tilemap with its sprite outputs, its opening or closing animation...
Definition uiwindow.h:11
u16 y
tiles
Definition uiwindow.h:16
u16 flags
UI_WINDOW_ flags; 0 once closing or free.
Definition uiwindow.h:25
u16 x
tiles
Definition uiwindow.h:15
#define RENDER_ENTRY_MASK
Definition tbs_edition.h:68
const u8 gUiText_KanjiGlyphs[]
s32 UiText_RenderStringTiles(u16 *text, u16 *tiles, u16 *mirror, s32 x)
Draws a string of 16-bit character codes with the window font into tiles of their own,...
Definition text_tiles.c:82
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed short s16
Definition types.h:12
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
#define UI_TILEMAP_VRAM
The UI tilemap in VRAM (BG screen block 4), which UiWork_UploadDirtyBlocks copies the work block's ti...
Definition window.h:51
#define UI_WORK
Definition window.h:267
@ UI_WINDOW_TEXT_CANVAS
text is drawn into a canvas of bitmap tiles (UiWindow_MapTextCanvasTiles)
Definition window.h:31
void UiWindow_PutGlyph(struct UiWindow *win, u32 tile, u32 x, u32 y, s32 mode)
Puts a character into a window's tilemap as a tile at tile (x, y) of its interior.
Definition sprites.c:187
s32 UiText_DrawGlyph(struct UiWindow *window, s32 character, s32 x, s32 y, s32 mode)
Draws a character of a window's text with its top-left corner at pixel (x, y) of the window's interio...
Definition sprites.c:17
What every part of the window object shares: its includes, edition values, macros and the codes of de...
@ TEXT_SPACE
@ TEXT_OUTLINE
the next entry is the outline colour
@ TEXT_COLOURS_RESET
@ TEXT_VOICED_MARK
dakuten
@ TEXT_SEMIVOICED_MARK
handakuten
@ TEXT_END_ALT
@ TEXT_NEWLINE
@ TEXT_COLOUR
the next entry is the text colour
@ TEXT_LINE_SPACING
the next entry is the line spacing
#define TEXT_CODE_VOICED
#define TEXT_CODE_SEMIVOICED
#define TEXT_CODE_MARK_SHIFT