Module gba::video

source ·
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§

Enums§

Type Aliases§

  • Data for a 4-bit-per-pixel tile.
  • Data for an 8-bit-per-pixel tile.