Mode 40 guide
Video Mode 40 is a simple attribute mode which most commonly could be used to produce 40 x 25 tile colored text or ASCII / ANSI graphics displays, reproducing similar look & feel games like text mode games on old 8 / 16 bit computers.
The best way to begin is to copy the [Mode 40 example] from the Uzebox master repo, and start off from that. It contains easy to activate examples for most of the mode's features.
The Video & Attribute RAM
When using the mode in its default configuration (40 x 25 tiles), you have got 1000 bytes (40 x 25) of VRAM which can be accessed by the Uzebox kernel's functions (so you can use Print and similar functions on it) and 2000 bytes (2 x 40 x 25) of ARAM (Attribute RAM) which specifies the Background (first byte) and Foreground (second byte) colors for each tile. By default the Background is filled with Black and the Foreground is filled with White (so even without initializing the ARAM, you will see your text output).
The character sets are contained in ROM. You don't need to provide them if you don't want to: the mode already contains some which you can activate with Makefile flags (set the flag '1' to activate the respective character ROM):
- M40_C64_GRAPHICS: Commodore 64 PETSCII Graphics character set (has only uppercase characters).
- M40_C64_ALPHA: Commodore 64 PETSCII Alphanumeric character set (has lowercase characters, but less graphics symbols).
- M40_C64_MIXED: Commodore 64 PETSCII Mixed character set, which is a mix of the two: the lower half (0 - 127) is Graphics, the higher half (128 - 255) is Alphanumeric.
- M40_MATTEL: Mattel Aquarius character set.
- M40_IBM_ASCII: IBM ASCII character set used on CGA monitors.
If you want to generate character sets, use [the generator] provided with the mode, it can convert Gimp exported headers to suitable C arrays.
Mixing character sets
Every tile row can have its own character set, you can set the character set using SetTileTableRow(). You can access the included character sets with the lowercase equivalent of the Makefile definitions (for example call SetTileTableRow(m40_c64_mixed, 10); to set Row 10 to Commodore 60 PETSCII Mixed, of course only works if you enabled that character set).
The mode provides simple blocky graphics display too which you can enable with the M40_TILEROW_1BPP or the M40_TILEROW_3BPP special character set codes (you can supply them to SetTileTable() to set the entire screen or SetTileTableRow() to set individual rows. They use the same VRAM and ARAM regions like the normal character mode.
The individual pixels of these modes can be accessed by the PutPixel and the GetPixel functions.
If you want to do something more advanced with them, you can do direct access, keeping in mind that the pixel layout is a little "weird".
1 bit per pixel mode layout
In 1 bit per pixel mode the ARAM contains pixel values and the VRAM contains foreground ('1' pixel) attributes (colors). The background color is taken from 'palette'. There are 4 bitmap rows in a tile row which get their pixels as follows:
- Row0: aram[(tile << 1) + 0].bit0, aram[(tile << 1) + 0].bit1, aram[(tile << 1) + 0].bit2, aram[(tile << 1) + 0].bit3
- Row1: aram[(tile << 1) + 0].bit4, aram[(tile << 1) + 0].bit5, aram[(tile << 1) + 0].bit6, aram[(tile << 1) + 0].bit7
- Row2: aram[(tile << 1) + 1].bit0, aram[(tile << 1) + 1].bit1, aram[(tile << 1) + 1].bit2, aram[(tile << 1) + 1].bit3
- Row3: aram[(tile << 1) + 1].bit4, aram[(tile << 1) + 1].bit5, aram[(tile << 1) + 1].bit6, aram[(tile << 1) + 1].bit7
3 bits per pixel mode layout
In 3 bits per pixel mode the ARAM and VRAM both contains pixel values, specifying color indices from 0 - 7 which colors are fetched from 'palette'. This is a planar mode where each byte specifies the pixels of a bitplane:
- Bitplane 0: aram[(tile << 1) + 0]
- Bitplane 1: aram[(tile << 1) + 1]
- Bitplane 2: vram[tile]
The pixel bit positions of each byte are laid out in the 4 bitmap rows as follows:
- Row0: bit0, bit1
- Row1: bit2, bit3
- Row2: bit4, bit5
- Row3: bit6, bit7
You can specify the size of the display compile time with the VRAM_TILES_H (Horizontal) and the VRAM_TILES_V (Vertical) definitions. This affects the memory consumption of the video mode which is 3 * VRAM_TILES_H * VRAM_TILES_V bytes.
At runtime you can use the SetRenderingParameters() kernel function to adjust the height and position of the screen. For example you can remove the top & bottom borders to gain more CPU cycles for your game with the following call:
SetRenderingParameters(FIRST_RENDER_LINE + SCREEN_BORDER_V, VRAM_TILES_V * TILE_HEIGHT);
(Of course you can also eliminate the border by setting SCREEN_BORDER_V zero in your Makefile if you don't want the border at all)
The mode tries to center the active area within the allowed vertical region. To restore the original setup, use: