This folder holds The Broken Seal's window system and the screens built on it: the windows drawn into a shared BG tilemap, the message channels that type text into them, the message decoder, the sprites windows carry and the icons, and the screens made of windows: the selection row, the option and system menus, the party status window, the save file menu, name entry, the status screen, the battle menus and the debug menus.
See also: Menus and Shops, the screens built on these windows.
| File | What it holds |
|---|---|
| window.c | the guide to the window object: it includes window_internal.h, then the parts in window/ in ROM order |
| battle_command.c | the guide to the menu object, from the party status window to the debug menus: it includes battle_command_internal.h, then the parts in battle_command/ in ROM order |
| glyph_arm.c | the text canvas renderer, compiled as ARM code and copied to RAM to run |
| articles.c | each edition's articles and possessives, which the decoder writes before names |
| scales.c | sprite scales, motion curves and the window colour wheel |
| text_speed.c | the message speed tables |
| windata.s, keyboard.s | glyph widths, text colours, the party status columns, the name entry keyboards |
| cursor.s, cursor_frame.s, fixed_block.s, slider.s, slidpal.s | sprite tiles and palettes, built from the PNGs beside them or under games/tbs/src/menu and games/tbs/src/graphics |
Each guide's comment says where to start, and each part's second line says what it holds: head -2 window/*.c battle_command/*.c lists them. A part includes its object's private header, so it resolves when opened on its own, but it is compiled only through its guide. The ROM shows each of the two objects as one; the parts are ours, cut where one family ends and the next begins. Link order is in games/tbs/objects.tsv, from glyph_arm.
The unit headers are in games/tbs/include/unit/window/. Its window.h also holds what both objects use: the UI tilemap's tiles (UI_TILE_), the window flags (UI_WINDOW_), sprite motions (UI_SPRITE_), message argument kinds (MSG_ARG_) and the DMA control words (DMA_COPY32 and its kin).
| Prefix | What it acts on |
|---|---|
| UiWork_ | the work block and its per-frame updates |
| UiWindow_ | a window's rectangle of the tilemap: frames, fills, dividers, tiles |
| UiText_ | messages and text: decoding, measuring and drawing |
| RenderOutput_ | the render output pool and a window's output list |
| UiIcon_, ItemIcon_, UiGlyph_ | icons built into sprite tiles |
| SelectionScreen_, Menu_ | the selection row, and the menus built from command icons |
| OptionMenu_, SystemMenu_, WindowColor_, PaletteGlow_ | the option and system menus and the window colours |
| SaveState_, SaveMenu_ | save files and the save file menu |
| NameEntry_, PartyTalkMenu_, DjinnMenu_, SummonMenu_, ItemList_, BattleMenu_, BattleTarget_ | the screens they name |
| Resource_, RenderResource_, Graphics_, Vram_ | things the engine names elsewhere: VRAM cache entries, pictures and video registers |
The Ui_ functions left have no family yet, and each is also used in another folder. Many names here are shared with The Lost Age's twins and with the far-call tables (system/far_call/WINDOW.S), so a rename crosses folders.
The spellings some sites keep to match, and the comment markers, are in Matching.
Showing a message takes three steps, each owned by a different piece, so that the slow part happens once and the typing costs little each frame.
Decoding.** UiText_BuildRenderEntries (window/decode.c) turns a message into decoded text all at once. Messages are Huffman coded with one tree per previous symbol: the code just decoded picks the tree for the next (Text_MessageContexts), so common pairs of letters cost few bits. The routine that walks the trees is ARM code; it is copied into heap slot 50 for the decode and released at the end (the C form, UiText_DecodeSymbol, is in the ROM but unused). As it decodes, it writes out what the message only refers to: names, numbers, item and ability names from the argument table (UiWork_PushValueSlot, MSG_ARG_), and the articles, possessives and endings each language needs (articles.c). Style codes (colours, pauses, page breaks) are kept with their operands for the channel.
The ring.** Decoded text goes into work->entries, a ring of 16-bit codes indexed with a mask (RENDER_ENTRY_MASK). Each message is written after the last one, ends with a 0, and is known only by the index it starts at, which UiText_BuildRenderEntries returns (and -1 asks for the last one again). Nothing owns a message's place in the ring: it stays readable until enough later decoding wraps round onto it. That is what lets several windows show text at once without any allocation. A message is cut off at the ring's length. The Japanese release has a ring of 256 codes and 12 windows; every other edition has 512 codes and 8 windows (TBS_PATCH_1 in include/tbs_edition.h), the same work block traded differently. XXX: that the ring was doubled for the longer European text is the likely reason; the bytes show only the change.
Typing.** A channel (struct UiChannelSlot) types decoded text into one window: it holds the window, the pen position in 1/256 pixels, the index of the next code, a countdown to the next character and the current style. UiText_QueueRenderEntries takes the first free channel and returns NULL when all three are busy, so at most three messages type at any moment; UiText_StartBattleMessage also reuses a channel whose window has finished, continuing below its last line. Typing is spread over frames because it is a task: UiWork_ProcessAll, the window system's scheduled routine, runs every frame, windows first (opening and closing), then the channels, then the sprites the windows carry, while the code that showed the message waits. XXX: why three channels is not known.
A window is a framed rectangle of one shared tile map, 32 tiles wide and 20 tall (work->tilemap, copied to UI_TILEMAP_VRAM), so every window shares one background and one set of tiles. Its text is drawn in one of three ways, chosen by flags: into bitmap tiles of the text canvas (UI_WINDOW_TEXT_CANVAS, drawn by glyph_arm.c from RAM), as one 16 by 16 sprite a character, or as tiles of the tile map itself. The canvas holds 120 tiles, the interior of one full-width window six tiles tall, so it serves one window at a time; labels and icons are sprites, from the render outputs and the sprite VRAM cache. work->tileAttributes remembers which text tiles the tile map still shows, so that redrawing a string can reuse the tiles it already has.
The names come from what each piece does on screen: windows, channels and render outputs from their structs' use, the control codes from what the decoder does with each, the screens from the English release's text they show. The message names are linker symbols made from their English text.
Still unknown:
Source: src/window