Alchemy
Loading...
Searching...
No Matches

glyph_arm.c

Go to the documentation of this file.
2#include "types.h"
3#include "uiwindow.h"
4#include "glyph.h"
5#include "text_font.h"
6#include "edition.h"
7#include "graphics.h"
9
10#define TEXT_CANVAS_PIXEL_HEIGHT 32
11#define SCREEN_TILE_ROWS 20
12#define SCREEN_TILE_COLUMNS 30
13
14// The text canvas renderer, compiled as ARM code and copied to RAM to run.
15//
16// A text window draws its text into a canvas of 4bpp tiles in VRAM
17// (UI_CANVAS_VRAM, mapped by UiWindow_MapTextCanvasTiles). The canvas tiles
18// run down columns: each column of tiles is as tall as the window's interior,
19// which is the window height less its two frame rows.
20
21/// Sets one pixel in the column-major text canvas. windowHeight includes the
22/// two frame rows; doubledPixelRow is twice the row within a tile.
23/// repeatedColor holds the colour index in all four nibbles.
24static __inline__ void UiText_SetCanvasPixel(u32 windowHeight, u32 x, u32 tileY,
25 u32 doubledPixelRow, u8 *canvas,
26 u32 repeatedColor) {
27 u16 *pixelHalfword;
28 u32 pixelMask;
29
30 pixelHalfword =
31 (u16 *)(((u32)canvas + (((x >> 3) * (windowHeight - 2) + tileY) << 5)) |
32 ((doubledPixelRow | ((x & 7) >> 2)) << 1));
33 pixelMask = 15 << ((x & 3) << 2);
34 *pixelHalfword = (*pixelHalfword & ~pixelMask) | (pixelMask & repeatedColor);
35}
36
37/// Draws one character into a window's text canvas with its top-left corner at
38/// pixel (x, y) of the window's interior, and returns how far the text
39/// advances.
40///
41/// With font set, the character comes from that small font: the 10-row, 1bpp
42/// kana and numeral font in Japanese, or an 8x8 two-colour font elsewhere. With
43/// no font, it comes from the main font (gUiText_Glyphs, and in Japanese
44/// gUiText_KanjiGlyphs for codes from 256), drawn in four passes: the first
45/// three draw an outline in colour 5 (offset left, right and down when the
46/// window has UI_WINDOW_OUTLINED_TEXT) and the last draws the glyph itself in
47/// colour 1. In Japanese, kana marks (codes 222 and 223) sit over the previous
48/// character and advance by 0.
49s32 UiText_DrawGlyphArm(struct UiWindow *window, u32 character, u32 x, u32 y,
50 const u8 *font) {
51 const u16 *glyphRows;
52 u32 glyphWidth;
53 u32 outlinePass;
54#if (LANGUAGE == LANGUAGE_JAPANESE) || (LANGUAGE == LANGUAGE_ENGLISH)
55 u32 advance;
56#endif
57 u32 windowHeight;
58 u32 row;
59 u32 nextRow;
60 u32 column;
61#if (LANGUAGE == LANGUAGE_ENGLISH)
62 u32 glyphIndex;
63#endif
64#if (LANGUAGE == LANGUAGE_JAPANESE)
65 /* FAKEMATCH: these records reserve the native frame's 64-byte unused area.
66 * Without them 6 of 193 differ in tbs-ja (sub sp, #36 for #100, and the
67 * stacked argument's offset). */
68 UNUSED struct RenderInput unusedFrame[4];
69#endif
70
71#if (LANGUAGE == LANGUAGE_ENGLISH)
72 // The English font accepts printable codes 32 through 143.
73 glyphIndex = character - 32;
74#endif
75 windowHeight = window->height;
76#if (LANGUAGE == LANGUAGE_ENGLISH)
77 if (glyphIndex > 111)
78 return 1;
79#endif
80
81#if (LANGUAGE == LANGUAGE_JAPANESE) || (LANGUAGE == LANGUAGE_ENGLISH)
82 if (character <= 255 || (font != NULL && character - 222 <= 1))
83#else
84 if (character <= 255 || font != NULL)
85#endif
86 {
87 if (font != NULL) {
88 const u8 *source;
89 u32 color;
90#ifdef MODERN
91 // A current GCC cannot see that the first column loads it.
92 u32 bits = 0;
93#else
94 u32 bits;
95#endif
96
97#if (LANGUAGE == LANGUAGE_JAPANESE)
98 u32 fontWidth;
99
100 color = 0x1111;
101 fontWidth = 8;
102 x++;
103 if (character - 222 <= 1) {
104 character += 32;
105 x -= 2;
106 y--;
107 fontWidth = 2;
108 }
109 character -= 32;
110 source = font + character * 10;
111 row = 0;
112 bits = *source++;
113 while (y + row < TEXT_CANVAS_PIXEL_HEIGHT) {
114 u32 tileY;
115 u32 rowLine;
116 u8 *vram;
117
118 column = 0;
119 /* FAKEMATCH: needed to match: the row increment is written in both
120 * arms, which puts ADD between CMP and BEQ; written once ahead of the
121 * test it is scheduled before CMP (JA differ 2). */
122 if (bits == 0)
123 nextRow = row + 1;
124 else {
125 nextRow = row + 1;
126 tileY = (y + row) >> 3;
127 vram = UI_CANVAS_VRAM;
128 rowLine = ((y + row) & 7) << 1;
129 do {
130 if (bits & 1)
131 UiText_SetCanvasPixel(windowHeight, x + column, tileY, rowLine,
132 vram, color);
133 column++;
134 bits >>= 1;
135 } while (bits != 0);
136 }
137 row = nextRow;
138 if (row > 9)
139 break;
140 bits = *source++;
141 }
142#else
143 u32 foregroundColor;
144 u32 secondaryColor;
145 u32 fontWidth;
146
147 source = font + character * 32;
148 foregroundColor = 0x1111;
149 secondaryColor = 0x3333;
150 row = 0;
151#if (LANGUAGE == LANGUAGE_ENGLISH)
152 fontWidth = gUiText_GlyphWidths[glyphIndex];
153#else
154 fontWidth = gUiText_GlyphWidths[character - 32];
155#endif
157 u8 *vram;
158
159 vram = UI_CANVAS_VRAM;
160 while (1) {
161 u32 tileY;
162 u32 rowLine;
163
164 column = 0;
165 nextRow = row + 1;
166 tileY = (y + row) >> 3;
167 rowLine = ((y + row) & 7) << 1;
168 while (1) {
169 if ((column & 1) != 0)
170 bits >>= 4;
171 else
172 bits = *source++;
173 if ((bits & 13) == 1) {
174 color = secondaryColor;
175 if ((bits & 15) == 1)
176 color = foregroundColor;
177 if (((x + column) >> 3) < SCREEN_TILE_COLUMNS)
178 UiText_SetCanvasPixel(windowHeight, x + column, tileY, rowLine,
179 vram, color);
180 }
181 column++;
182 if (column > 7)
183 break;
184 }
185 row = nextRow;
186 if (nextRow > 7 || y + nextRow >= TEXT_CANVAS_PIXEL_HEIGHT)
187 break;
188 }
189 }
190#endif
191 return fontWidth;
192 }
193 // Main-font entries begin with their advance width.
194 glyphRows =
195 (const u16 *)((const u8 *)gUiText_Glyphs + (character - 32) * 26);
196 glyphWidth = *glyphRows++;
197 } else {
198#if (LANGUAGE == LANGUAGE_JAPANESE)
199 glyphWidth = 10;
200 glyphRows = (const u16 *)(gUiText_KanjiGlyphs + (character - 256) * 24);
201#else
202 glyphRows =
203 (const u16 *)((const u8 *)gUiText_Glyphs + (character - 32) * 32);
204 glyphWidth = *glyphRows;
205 glyphRows += 4;
206#endif
207 }
208#if (LANGUAGE == LANGUAGE_JAPANESE) || (LANGUAGE == LANGUAGE_ENGLISH)
209 if (character - 222 <= 1) {
210 x -= 3;
211 y -= 2;
212 advance = 0;
213 } else
214 advance = glyphWidth;
215#endif
216
217 // Draw the three outline offsets first, then the foreground pixels.
218 for (outlinePass = 0; outlinePass <= 3; outlinePass++) {
219 u32 color;
220 u32 bits;
221 u8 *vram;
222 const u16 *nextGlyphRow;
223
224 if (outlinePass == 3)
225 color = 0x1111;
226 else
227 color = 0x5555;
228 if (window->flags & UI_WINDOW_OUTLINED_TEXT) {
229 if (outlinePass <= 1) {
230 if (outlinePass == 1)
231 x += 2;
232 else
233 x--;
234 } else if (outlinePass == 2) {
235 x--;
236 y++;
237 } else
238 y--;
239 }
240 row = 0;
241 bits = glyphRows[0];
242 bits <<= 16;
243 nextGlyphRow = glyphRows + 1;
245 vram = UI_CANVAS_VRAM;
246 while (1) {
247 u32 tileY;
248 u32 rowLine;
249
250 column = 0;
251 nextRow = row + 1;
252 tileY = (y + row) >> 3;
253 rowLine = ((y + row) & 7) << 1;
254 while (1) {
255 if ((s32)bits < 0)
256 UiText_SetCanvasPixel(windowHeight, x + column, tileY, rowLine,
257 vram, color);
258 bits <<= 1;
259 if (bits == 0)
260 break;
261 column++;
262 if (column > 13)
263 break;
264 }
265 row = nextRow;
266 if (nextRow > 11)
267 break;
268 bits = *nextGlyphRow++;
269 bits <<= 16;
270 if (y + nextRow >= TEXT_CANVAS_PIXEL_HEIGHT)
271 break;
272 }
273 }
274 }
275#if (LANGUAGE == LANGUAGE_JAPANESE) || (LANGUAGE == LANGUAGE_ENGLISH)
276 return advance;
277#else
278 return glyphWidth;
279#endif
280}
281
282/// Builds the hardware window's horizontal extent for each of the screen's
283/// 160 scanlines from frameTiles in the UI tilemap (32 tiles a row,
284/// 30 shown). Each scanline gets (left << 8) | right, the WINxH format, written
285/// to the second halfword of its pair in scanlineBounds. A row without a frame
286/// gets 0. The rounded corner tiles trim the first or last scanline of a row by
287/// one pixel on that side, so the window follows the frame's rounded corners.
288void Tile_BuildMetatiles(u16 *scanlineBounds, u16 *frameTiles) {
289 u32 tileRow;
290 u32 tileColumn;
291 s32 left;
292 s32 right;
293 s32 topLeft;
294 s32 bottomLeft;
295 s32 topRight;
296 s32 bottomRight;
297 s32 foundLeftEdge;
298 s32 horizontalBounds;
299
300 for (tileRow = 0; tileRow < SCREEN_TILE_ROWS; tileRow++) {
301 bottomLeft = 0;
302 left = bottomLeft;
303 topLeft = bottomLeft;
304 bottomRight = bottomLeft;
305 right = bottomRight;
306 topRight = bottomRight;
307 foundLeftEdge = bottomRight;
308 tileColumn = bottomRight;
309 scanlineBounds++;
310 for (; tileColumn < SCREEN_TILE_COLUMNS; tileColumn++) {
311 u16 tile = *frameTiles++;
312
313 if (tile == 0)
314 continue;
315 // The first frame tile establishes the left edge and a one-tile span.
316 // A later right frame tile extends that span.
317 if (foundLeftEdge == 0) {
318 switch (tile) {
319 case 0xf010: // top-left corner
320 left = tileColumn * 8;
321 right = left + 8;
322 topLeft = left + 1;
323 bottomLeft = left;
324 topRight = bottomLeft + 7;
325 bottomRight = right;
326 foundLeftEdge++;
327 break;
328 case 0xf013: // bottom-left corner
329 left = tileColumn * 8;
330 right = left + 8;
331 topLeft = left;
332 bottomLeft = left + 1;
333 topRight = right;
334 bottomRight = left + 7;
335 foundLeftEdge++;
336 break;
337 case 0xf007:
338 case 0xf016: // left side
339#if LANGUAGE != LANGUAGE_JAPANESE
340 case 0xf01a:
341#endif
342 left = tileColumn * 8;
343 right = left + 8;
344 bottomLeft = left;
345 topLeft = bottomLeft;
346 bottomRight = right;
347 topRight = bottomRight;
348 foundLeftEdge++;
349 }
350 } else {
351 switch (tile) {
352 case 0xf012: // top-right corner
353 right = tileColumn * 8 + 8;
354 topRight = tileColumn * 8 + 7;
355 bottomRight = right;
356 break;
357 case 0xf015: // bottom-right corner
358 right = tileColumn * 8 + 8;
359 topRight = right;
360 bottomRight = tileColumn * 8 + 7;
361 break;
362 case 0xf007:
363 case 0xf017: // right side
364#if LANGUAGE != LANGUAGE_JAPANESE
365 case 0xf01b:
366#endif
367 bottomRight = tileColumn * 8 + 8;
368 right = bottomRight;
369 topRight = bottomRight;
370 break;
371 }
372 }
373 }
374 // The tileRow's eight scanlines: its top line, six middle lines and its
375 // bottom line.
376 horizontalBounds = topRight + (topLeft << 8);
377 *scanlineBounds++ = horizontalBounds;
378 horizontalBounds = right + (left << 8);
379 scanlineBounds++;
380 *scanlineBounds++ = horizontalBounds;
381 scanlineBounds++;
382 *scanlineBounds++ = horizontalBounds;
383 scanlineBounds++;
384 *scanlineBounds++ = horizontalBounds;
385 scanlineBounds++;
386 frameTiles += 2;
387 *scanlineBounds++ = horizontalBounds;
388 scanlineBounds++;
389 *scanlineBounds++ = horizontalBounds;
390 scanlineBounds++;
391 *scanlineBounds++ = horizontalBounds;
392 horizontalBounds = bottomRight + (bottomLeft << 8);
393 scanlineBounds++;
394 *scanlineBounds++ = horizontalBounds;
395 }
396}
The edition's language, for C to compare (LANGUAGE == LANGUAGE_GERMAN).
Font glyphs and their palettes.
const struct FontGlyph gUiText_Glyphs[]
s32 UiText_DrawGlyphArm(struct UiWindow *window, u32 character, u32 x, u32 y, const u8 *font)
Draws one character into a window's text canvas with its top-left corner at pixel (x,...
Definition glyph_arm.c:49
#define TEXT_CANVAS_PIXEL_HEIGHT
Definition glyph_arm.c:10
void Tile_BuildMetatiles(u16 *scanlineBounds, u16 *frameTiles)
Builds the hardware window's horizontal extent for each of the screen's 160 scanlines from frameTiles...
Definition glyph_arm.c:288
#define SCREEN_TILE_COLUMNS
Definition glyph_arm.c:12
static __inline__ void UiText_SetCanvasPixel(u32 windowHeight, u32 x, u32 tileY, u32 doubledPixelRow, u8 *canvas, u32 repeatedColor)
Sets one pixel in the column-major text canvas.
Definition glyph_arm.c:24
#define SCREEN_TILE_ROWS
Definition glyph_arm.c:11
The screen blend's globals and the graphics routines.
const u8 gUiText_GlyphWidths[]
#define NULL
Definition bilibin.h:6
A 16-byte record of a rectangle.
u16 y
not named by TBS code
u16 x
not named by TBS code
A window: a framed rectangle of the tilemap with its sprite outputs, its opening or closing animation...
Definition uiwindow.h:11
u16 flags
UI_WINDOW_ flags; 0 once closing or free.
Definition uiwindow.h:25
u16 height
tiles
Definition uiwindow.h:14
The kanji glyphs and the text marks drawn with characters.
const u8 gUiText_KanjiGlyphs[]
The integer types, TRUE, UNUSED and the fixed-address macros.
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
UiWindow, a window's work, and marking its tilemap rows for transfer.
#define UI_CANVAS_VRAM
Definition window.h:45
@ UI_WINDOW_OUTLINED_TEXT
the canvas text gets an outline
Definition window.h:35