To display a frame, Studio decodes its rows, combines or shifts previous-frame data where required, applies layer visibility and colours, then transfers the composed image to the screen. The original-ROM research follows the functions and buffers used for these steps. The PPM wiki describes how the input data is encoded in the file. [1][2]
Format-4 rows and palette
The research distinguishes packed working layers from expanded display data and records how palette generation and commits fit into presentation. It also maps batch export and indexed-frame paths. Those observations help explain why a thumbnail, a file frame and a screen buffer should not be treated as the same bitmap. [1]
Visibility flags must affect output without destroying hidden layer data. Compare a decoder against known files with both layer colours, both paper colours, translated frames and hidden-layer settings. [1][2]
Two representations of a frame
PPM stores compressed rows. The editor and player work with decoded layer buffers, and the final display path expands them into a presentation image. These buffers have different row strides and are managed by different parts of the program. Decode the frame, apply its palette and combine the layers before comparing it with screen memory. [1][2]
Format-4 rows
The research follows the format-4 row decoder and compares the rewritten implementation with original code on a specific set of inputs. Two-bit row codes select empty, sparse and fully present chunk paths. The decoder reads row masks and ink bytes while respecting the frame's two layers. A single wrongly advanced byte can desynchronise all later rows, so validate consumed size against the frame extent. [1][2]
Palette and display upload
The frame supplies paper and two ink choices. The display path then applies visibility, compositing and a palette before committing pixels to screen buffers. Separate functions handle indexed-frame rendering and batch export. Rendering an online TMB, a PPM thumbnail and a full PPM frame through one generic bitmap function will miss these format differences. [1]
Test matrix
Use both paper colours; ink on each layer separately and overlapped; a hidden layer; a difference frame with translation; and a frame after a seek. Compare not only visible pixels but decoder byte consumption and next-frame state. [1][2]
Original rendering functions
The rendering code includes a format-4 row decoder, general, packed and special renderers, a palette generator and a handler for pending display updates. The US V2 loaded ARM9 entries are 02012DE4, 020133E4, 020135C8, 02013774, 02014C7C and 02011D54. The corresponding functions have different addresses in the other three Studio builds. Use the build-aware atlas before following a call graph. [1]
Intermediate buffers and frame selection
Two packed input layers each occupy 0x1800 bytes. The row-decoded workspace is 0x3000 bytes and expanded output/scratch transfers use 0xC000 bytes. The indexed-frame routine reads a frame offset using the low 16 bits of the incoming index, but stores the full index in metadata after presentation. Index zero clears a working buffer; later parity selects which buffer holds prior state. These distinct widths matter when studying artificial large indexes. [1]
The format-4 decoder starts with a 96-byte table holding two-bit row kinds for 384 rows. A kind-zero row needs no payload; kinds one and two read a big-endian 32-bit presence mask and one byte for each set bit, using respectively zero or 0xFF for absent chunks; kind three copies 32 bytes. Its return value is the advanced payload pointer. The inspected decoder has no local input-length check, so a safe external reader must validate bounds before calling an equivalent routine. [1][2]
Palette and pending transfer
Palette generation fills 256 halfword entries. Layer flag bits 0x80 and 0x40 select colour sources; when both are set, layer zero wins in the observed branch. JP V1 has one six-halfword bank per theme and cases 0–11; V2 chooses one of four banks and adds cases 12–13. The generator leaves unspecified entries untouched. Palette commit transfers 512 bytes to 05000400. A separate pending-update handler checks metadata byte one, clears it before retrieving the display destination, transfers 0xC000 image bytes and then commits the palette. That early clear can affect the destination getter's branch. [1]
Do not confuse the two frame paths
Document-frame decoding and per-application-frame upload are related but separate. The application frame service collects 12-byte source records into bucket lists, packs eight-byte output records, then transfers them with 16-byte matrix records. A code path named “FrameBegin” is not necessarily selecting the next PPM image. Check which buffer, index and hardware destination the function uses before identifying it as part of the player. [1]
