Tiles in Basic I – Mode 0 and 1
One of the important skills we need to master in order to design efficient games is different tile modes available on Commander X16. It might look complex at first glance but it is really not that complicated if
we discuss it step by step. If we check the official
Commander X16 documentation there are following five tile modes available:
0 – 1 bit per pixel tiles– 16 colors
1 – 1 bit per pixel tiles– 256 colors
2 – 2 bits per pixel tiles
3 – 4 bits per pixel tiles
4 - 8 bits per pixel
tiles
We can clarify one thing immediately. When we are in text mode typing in BASIC programs we are essentially already in tile mode and tiles are simply PETSCII characters of size 8x8 pixels.
We have two layers at our disposal. We can think of layers as
two screens above each other and each can have its own settings and memory
location etc. Everything we will say about one layer also applies to the other, so
let’s just focus on one at the moment. Each layer has 7 dedicated registers that
define their appearance and behavior:
Layer 0 - $9F2D - $9F33
Layer 1 - $9F34 - $9F3A
Register | Address | Name | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
---|---|---|---|---|---|---|---|---|---|---|
9-0 | $9F29 | Video | Current Field | Sprite Enable | Layer 1 Enable | Layer 0 Enable | NTSC/RGB 240p | Chroma Disable | Output Mode | |
10-0 | $9F2A | Horiz. Scale | Active Display Horizontal Scale | |||||||
11-0 | $9F2B | Vert. Scale | Active Display Vertical Scale |
We see several interesting things in these registers. The most important ones for this topic are bits 4 and 5. We already covered Bit 6 in post about sprites. So what is the default mode after turning on Commander X16? Let’s
check:
PRINT PEEK($9F29)
Returns 33 or 161 which is 0010 0001 or 1010 0001 in binary. We can ignore bit 7 at this time, but let us look at other bits.
We see that Layer 0 is disabled (0 on bit 4 position)
and that default text mode is using Layer 1 (bit 5 is set to 1).
Registers 10-0 and 11-0 are also very interesting because they define how much of the video screen we actually see. let's check their value after fresh start:
PRINT PEEK($9F2A)
PRINT PEEK($9F2B)
both return 128 or 1000 0000 in binary. What that means is that every pixel in memory will show as one pixel on screen or in other words if we have 128 in both registers we see maximum resolution of screen which is 80 x 60 characters (or tiles). if we poke value 64 into them we scale the pixels by 2 so every pixel is expanded to 2 pixels, by poking 32 they are expanded by 4 and so on.
so if we do following:
POKE $9F2A,128
POKE $9F2B,64
we create 80 x 30 screen mode and so on. So in extreme by poking ones into these two registers we stretch just handful of pixels across the whole screen. Of course most of the values beyond e.g. 32 are not very useful except for some effects like below:
Since Layer 0
is disabled we can disregard it for now and study Layer 1 a little bit closer
by checking seven dedicated registers. Last four are used for scrolling which we will
not look at now, that is a topic that is covered in separate post.
Register | Address | Name | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
---|---|---|---|---|---|---|---|---|---|---|
20 | $9F34 | Layer 1 - Config | Map Height | Map Width | T256C | Bitmap Mode | Color Depth | |||
21 | $9F35 | Layer 1 - Mapbase | Map Base Address Bits 9 - 16 | |||||||
22 | $9F36 | Layer 1 - Tilebase | Tile Base Address Bits 11 - 16 | Height | Width | |||||
23 | $9F37 | Layer 1 - H Scroll | Horizontal Scroll Bits 0 - 7 | |||||||
24 | $9F38 | Layer 1 H Scroll | - | Horizontal Scroll Bits 8 - 11 | ||||||
25 | $9F39 | Layer 1 - V Scroll | Vertical Scroll Bits 0 - 7 | |||||||
26 | $9F3A | Layer 1 - V Scroll | - | Vertical Scroll Bits 8 - 11 |
Starting with register 20, it defines the core characteristics of the layer of which the size is determined using two bits for both height and width and is defined in tiles with following values:
00 – 32 tiles in that direction
01 – 64 tiles in that direction
10 – 128 tiles in that direction
11 – 256 tiles in that direction
So that means that each layer can have 16 possible
dimensions: 32 x 32 tiles, 32 x 64 tiles, 32 x 128 tiles etc. all the way up to
256 x 256 tiles which is quite large. If we add to this that each tile can be 8
or 16 pixels in each direction the possible size of each layer is very large.
Both these extreme dimensions are not very practical so in
real life we will almost always work with smaller sizes
Bit 3 (T256C) is also very important. It is used to distinguish between Mode 0 and 1 - 16 colors or 256 colors available per tile (or character). Let's check the defaults again:
PRINT PEEK($9F34)
returns 96 or 0110 000 in binary.
If we analyze what this value means it is clear that our default text mode is:
64 tiles high
128 tiles wide
Uses 16 color mode
Is not in graphics mode
Color depth is 00
Color depth has therefore 4 possible values:
00 - 1 bit per pixel
01 - 2 bits per pixel
10 - 4 bits per pixel
11 - 8 bits per pixel
At this time we have to also emphasize one very important fact:
Since the layer size is defined in tiles it is also important to understand what is the size of tiles. Tile sizes are defined in bits 0 and 1 of register 22.
Tile Height and Tile Width have following values:
0 – each tile is 8 pixels in that direction
1 – each tile is 16 pixels in size
This means that tiles can be 8x8, 8x16, 16x8 or 16x16 pixels.
At this time we have to also emphasize one very important fact:
Layers as they are
defined in the memory do not determine what and how much of them are shown on
the screen. That is determined in Display Composer which we will look at some
other time.
Let’s again explore default state of the display at start
and see if all we said above makes sense:
PRINT PEEK($9F36)
Returns 248 or 1111 1000
We see that bits 0 and 1 are both 0 meaning that by default we use 8
pixel X 8 pixel tiles, which of course makes sense because we already know that Commander X16 fonts are 8x8 pixels in size.
Register 21 and 22 contain pointers to different parts of video memory
where data is stored. The following image explains why we need two pointers:
one is pointing to tile definitions and the other to the display map which we
sometimes refer to as screen memory.
The picture above also describes the fundamental difference
between bitmap modes and tile modes.
In bitmap modes we manipulate pixels directly in the screen memory whereas in tile mode we store just indexes to tiles and tile definitions separately. This mode sounds much more complicated so there must be some real reasons why we do it this way. The answer is speed. We can define tiles once and then reuse the same tile over and over on the screen by adding simple index which is 1-2 bytes instead of 8 bytes for 8x8 tiles or even 32 bytes for 16x16 tiles. If we use tiles, VERA does the heavy lifting for us and we can use CPU cycles for something else. Of course bitmap modes are great for some other uses that just can’t be achieved with tiles for example math graphing, proportional text, graphical UI like GEOS, etc.
In bitmap modes we manipulate pixels directly in the screen memory whereas in tile mode we store just indexes to tiles and tile definitions separately. This mode sounds much more complicated so there must be some real reasons why we do it this way. The answer is speed. We can define tiles once and then reuse the same tile over and over on the screen by adding simple index which is 1-2 bytes instead of 8 bytes for 8x8 tiles or even 32 bytes for 16x16 tiles. If we use tiles, VERA does the heavy lifting for us and we can use CPU cycles for something else. Of course bitmap modes are great for some other uses that just can’t be achieved with tiles for example math graphing, proportional text, graphical UI like GEOS, etc.
However most games use tile system with heavy use of
hardware sprites to enable smooth movement of objects.
As we saw in the example above, text mode is just one type of Tile mode where each character is just 8x8 pixel tile.
Let’s continue to verify that all we said is true and check the content of these pointers for default screen.
PRINT PEEK($9F35) returns 216 or 1101 1000 in binary, which means that default Map Base is pointing at $1B000 in VRAM. Why is that?
As we seem Map Base register only contains bits 9-16 so we need to shift $D8 left nine times (which means we add nine zeroes to the right
1101 1000
1101 1000 000000000
1 1011 0000 0000 0000 = 1 B000
Which we know is true because we
were using VPOKE to display characters in all other projects and games before.
Remember the formula:
VPOKE 1, $B000+Y*256+X*2,CharCode
It now makes sense right?
It is important to mention that we can't choose just any address for the start of video memory. Because we only have 8 bits for it and 128K bytes of memory to address therefore we can only set bits 9-16 and therefore aligned to every 512 bytes or $200 hexadecimal. so our memory can start at 0, 512, 1024,1536, etc. or more conveniently in hex at $0000, $0200, $0400, etc.
Changing Tiles
What about the Tile Map, can we do something with it?
We saw above that PEEK($9F36) returns the value of Register 22. We also saw that bits 0 and 1 determine the size of tiles so we only have 6 bits remaining to define pointer to tile maps.
Looking at description of registers above we see that it contains bits 11-16 so we can only set address in increments of 2048 bytes or $800 hex. So where
are we pointing at by default?
We put together results from registers above plus add 11 bits (0-10) of zeroes
%1111 10 00000000000
Or if we sort it properly:
%1 1111 0000 0000 0000
In hex this is $1F000
It means that our tiles or in this case character font should start at $1F000 in VRAM. And that is exactly where it is. VERA copies the data from ROM to that location. Alternatively we can make it also copy other character sets like ISO character set or lower case PETSCII.
For readers who don’t trust me let’s prove it by changing
one of the characters with a smiley face. The drawing for 8x8 representation is
below:
Luckily Commander X16 supports the binary numbers by default
so we don’t need to translate to decimal numbers like in “old times”. Since @
character is first one in the character set with index 0 we can redefine it
into smiley by simple eight VPOKEs like this:
And there we have it. Every time we type @ symbol now it is displayed as smiley face. In similar way we can redesign any of the 256 characters into some special symbols we might require or add letter from different alphabets.
Mode 1
Let’s now explore the Tile mode 1. It is very similar to the
default Mode 0. The only difference is in how VERA translates the color
attributes.
We can turn it on by simply setting Bit 3 of register 20 to 1 like this:
POKE $9F34,PEEK($9F34) OR %00001000
In Mode 0 only first 16 colors from palette are used but we can choose both background and text color so we have 256 different possibilities (some invisible when we use same color for background and foreground of course).
In Mode 1 all 256 colors from palette open up. Check the
default colors in this link:
Using all these colors is extremely simple. We can change the text to any of the 256 colors by simply poking the color index into the attribute bye (it is always odd number) for each character using following formula:
VPOKE 1, $B000+Y*256+X*2+1,Color Index
We have the whole rainbow of characters at our disposal now. There is one problem though. Now we can’t control the background color. One workaround is to use inverse characters but the text is always black.
The other way is to remember that Color 0 is actually
transparent and if we also remember that by default we are working on Layer 1
means that transparent color should show through the Layer 0 which is beneath
the Layer 1. So all we need to do is turn on the Layer 0 and configure it in
such a way that we can set different background colors that will show through.
Try doing it by yourself. If it doesn’t go below is short
program that does it and generates following "art":
Link to source
Link to source
Comments
Post a Comment