Expand description
Module to control the GBA’s screen.
§Video Basics
To configure the screen’s display, you should first decide on the
DisplayControl
value that you want to set to the
DISPCNT
register. This configures several things,
but most importantly it determines the VideoMode
for the display to use.
The GBA has four Background layers. Depending on the current video mode, different background layers will be available for use in either “text”, “affine”, or “bitmap” mode.
In addition to the background layers, there’s also an “OBJ” layer. This allows the display of a number of “objects”, which can move independently of any background. Generally, one or more objects will be used to display the “sprites” within a game. Because there isn’t an exact 1:1 mapping between sprites and objects, these docs will attempt to only talk about objects.
§Color, Bit Depth, and Palettes
Color values on the GBA are 5-bits-per-channel RGB values. They’re always
bit-packed and aligned to 2, so think of them as being like a u16
.
Because of the GBA’s limited memory, most images don’t use direct color (one
color per pixel). Instead they use indexed color (one palette index per
pixel). Indexed image data can be 4-bits-per-pixel (4bpp) or
8-bits-per-pixel (8bpp). In either case, the color values themselves are
stored in the PALRAM region. The PALRAM contains the BG_PALETTE
and
OBJ_PALETTE
, which hold the color values for backgrounds and objects
respectively. Both palettes have 256 slots. The palettes are always indexed
with 8 bits total, but how those bits are determined depends on the bit
depth of the image:
- Things drawing with 8bpp image data index into the full range of the palette directly.
- Things drawing with 4bpp image data will also have a “palbank” setting. The palbank acts as the upper 4 bits of the index, selecting which block of 16 palette entries the that thing will be able to use. Then each 4-bit pixel within the image indexes within the palbank.
In both 8bpp and 4bpp modes, if a particular pixel’s index value is 0 then that pixel is instead considered transparent. So 8bpp images can use 255 colors (+ transparent), and 4bpp images can use 15 colors (+ transparent). Each background layer and each object can individually be set to display with either 4bpp or 8bpp mode.
§Tiles, Screenblocks, and Charblocks
The basic unit of the GBA’s hardware graphics support is a “tile”.
Regardless of their bit depth, a tile is always an 8x8 area. This means that
they’re either 32 bytes (4bpp) or 64 bytes (8bpp). Since VRAM starts aligned
to 4, and since both size tiles are a multiple of 4 bytes in size, we model
tile data as being arrays of u32
rather than arrays of u8
. Having the
data stay aligned to 4 within the ROM gives a significant speed gain when
copying tiles from ROM into VRAM.
The layout of tiles within a background is defined by a “screenblock”.
- Text backgrounds use a fixed 32x32 size screenblock, with larger backgrounds using more than one screenblock. Each TextEntry value in the screenblock has a tile index (10-bit), bits for horizontal flip and vertical flip, and a palbank value. If the background is not in 4bpp mode the palbank value is simply ignored.
- Affine backgrounds always have a single screenblock each, and the size of
the screenblock itself changes with the background’s size (from 16x16 to
128x128, in powers of 2). Each entry in an affine screenblock is just a
u8
tile index, with no special options. Affine backgrounds can’t use 4bpp color, and they also can’t flip tiles on a per-tile basis.
A background’s screenblock is selected by an index (5-bit). The indexes go in 2,048 byte (2k) jumps. This is exactly the size of a text screenblock, but doesn’t precisely match the size of any of the affine screenblocks.
Because tile indexes can only be so large, there are also “charblocks”. This
offsets all of the tile index values that the background uses, allowing you
to make better use of all of the VRAM. The charblock value provides a 16,384
byte (16k) offset, and can be in the range 0..=3
.
§Priority
When more than one thing would be drawn to the same pixel, there’s a priority system that determines which pixel is actually drawn.
- Priority values are always 2-bit, the range
0..=3
. The priority acts like the sorting index, or you could also think of it as the distance from the viewer. Things with a lower priority number are closer to the viewer, and so they’ll be what’s drawn. - Objects always draw over top a same-priority background.
- Lower indexed objects get drawn when two objects have the same priority.
- Lower numbered backgrounds get drawn when two backgrounds have the same priority.
There’s also one hardware bug that can occur: when there’s two objects and their the priority and index wouldn’t sort them the same (eg: a lower index number object has a higher priority number), if a background is also between the two objects, then the object that’s supposed to be behind the background will instead appear through the background where the two objects overlap. This might never happen to you, but if it does, the “fix” is to sort your object entries so that any lower priority objects are also the lower index objects.
Modules§
- Module for object (OBJ) entry data.
Structs§
- An RGB555 color value (packed into
u16
). - An entry within a tile mode tilemap.
Enums§
- The video mode controls how each background layer will operate.
Type Aliases§
- Data for a 4-bit-per-pixel tile.
- Data for an 8-bit-per-pixel tile.