Difference between revisions of "Video Modes"
Line 46: | Line 46: | ||
|} | |} | ||
+ | [[File:Ktclash.png|200px|thumb|left|Color clash in a classic spectrum game. The corners of the knight's helmet appear green and red because they are in the same attribute cell as the plant and table respectively.]] | ||
Because you can have only one color value per 8x8 cell, some older games exhibited "color clash" in which an object or part of an object would appear the wrong color because it needed to be drawn inside an 8x8 cell with another object of a different color. | Because you can have only one color value per 8x8 cell, some older games exhibited "color clash" in which an object or part of an object would appear the wrong color because it needed to be drawn inside an 8x8 cell with another object of a different color. | ||
Revision as of 13:38, 16 August 2017
The Enhanced ULA adds extra video modes and features to the standard Spectrum.
Spectrum Video Mode
The standard Spectrum has only one video mode, with a resolution of 256x192 (not including the border) and 15 colours. This screen is further divided into 8x8 "attribute cells", so the attribute cell resolution is 32x24.
Pixel data is stored at $4000 onwards, with one bit per pixel, so each byte represents 8 pixels (ie, one line of an attribute cell). Each screen line is stored in straightforward left-to-right order, so the 32 bytes from $4000 onwards represent all the pixels on the first line of the screen.
Unfortunately, while the columns of the screen are in straightforward order, the lines are not.
The 192 line screen is vertically divided into thirds, with each third containing 64 lines (or 8 attribute cells). These three thirds are stored sequentially in memory, but within each third, the order is not what you'd expect. You'd expect it'd store the first line of the first cell, the second line of the first cell.. up to the eighth line of the first cell, then the first line of the second cell. Instead, the sorting is inverted. So it stores the first line of the first cell, then the first line of the second cell, then the first line of the third cell, and so on.. up to the first line of the eighth cell, which is then followed by the second line of the first cell!
This means that getting the address of the start of a given line can be a tricky business. Fortunately, since the numbers involved are all powers of 2, it can be done by breaking the line number (0-191) into its bits.
128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
---|---|---|---|---|---|---|---|
3rd | 3rd | V-Cell | V-Cell | V-Cell | Offset | Offset | Offset |
Each 3rd is 64 lines, so the top two bits of the line number indicate which 3rd we're in, with the highest being %10 for 128 (%11 would be 192, off the bottom of the screen). Then, each cell is 8 lines, so bits 3-5 of the line number give the cell address, and the remaining bits give the line within that cell.
The thirds are stored in sequential order; each third contains 64 lines; and storing a line takes 32 bytes, meaning that the 3rd number is multiplied by 2048. Add $4000 for the start of the screen and that'll give the address of the start of the target third. Now, to get to the block for the correct line number. To store the top line of a single row of cells takes 32 bytes; but since all the top lines for 8 cells are stored together, there's actually 256 bytes (32*8) between lines. So the offset must be multiplied by 256 and added to the address. Then, to select the correct cell within that block, the cell number needs to be multiplied by 32. So the final 16-bit address is:
32768 | 16384 | 8192 | 4096 | 2048 | 1024 | 512 | 256 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 3rd | 3rd | Offset | Offset | Offset | V-Cell | V-Cell | V-Cell | 0 | 0 | 0 | 0 | 0 |
The five lowest bits of this value are then used to select between the 32 horizontal cells on that line, which is simply done by dividing the pixel address by 8.
As you can see from the above, pixel data is stored with 1-bit color in the pixel data memory. However, it is possible for the color to vary across the screen. The snag is that you can set only two colours within a single attribute cell - that is, an 8x8 area.
Color data is stored at $5800 onwards. Unlike the pixel data, it's stored in straightforward reading order, with one byte per attribute cell, for a total of 768 bytes. The byte represents:
Bit | Function |
---|---|
0-2 | "Ink" color (color of 1 bits). From 0-7: black, blue, red, magenta, green, cyan, yellow, white. |
3-5 | "Paper" color (color of 0 bits). |
6 | Bright flag (toggles brighter version of both colors) |
7 | Flash flag (toggles regular alternation of ink and paper colors) |
Because you can have only one color value per 8x8 cell, some older games exhibited "color clash" in which an object or part of an object would appear the wrong color because it needed to be drawn inside an 8x8 cell with another object of a different color.
Timex Sinclair Video Modes
The Timex Sinclair added a number of new video modes which are controlled by Timex Sinclair Video Mode Control ($xxFF / 255). These modes are:
- Screen 0/Screen 1: this allows the location of pixel data to be changed between $4000 and $6000.
- Hi-Res: creates a 512x192 pixel screen by alternating columns from screen 0 and screen 1, but attributes are disregarded: the entire screen can only be two colours. Which two they are is configured via the control port.
- Hi-Color: uses the screen 1 memory area as an expanded attribute space where each attribute applies to an 8x1 area, rather than 8x8. This means that the areas within which only 2 colors are available are substantially smaller.
Radastan Mode
Radastan Mode allows 16 colors, selected from 256, anywhere on the screen - at the cost of halving the standard screen resolution to 128x96. Each pixel is assigned 4 bits instead of 1.
ULAPlus
ULAPlus allows 64 colors on screen at once via re-purposing the FLASH and BRIGHT bits as extra color bits. It also allows these colors to be selected from a palette of 256. It is controlled via ($BF3B) and ($FF3B).