Sprites in Basic I - Setup
We will take few basic steps and answer following questions:
- How to turn on the sprites
- Sizing and Colors
- Positioning
- Storing appearance
- We will not be using collision functionality for now
Important Addresses
Before we start coding let’s sketch video memory and registers that we will be using. As you probably know, VERA stands for Video Enhanced Retro Adapter and we can simply refer to it as video chip. We have to also understand that video memory is separate to main program memory and most direct way to access video memory is through VERA using VPOKE command. We will use following memory/addresses:Address Range | Description | How will we use it |
---|---|---|
$000000 - $1FFFF | Video RAM | To store sprite graphics and settings |
$1FA00 - $1FBFF | Palette | We will use default palette in our sprite |
$1FC00 - $1FFFF | Sprite Attributes | To define appearance of our sprites and to point to sprites definition and position on screen |
Video RAM
Video RAM is 128K of memory that can be used for display and
for storing other video related data that needs to be accessed by VERA. We will
use it to store sprite graphics. Remember that Sprites are independent from
other displayed data so it is very common to display Sprites over text or tile
modes. Let’s remind us how much memory standard text modes use:
SCREEN 0 – 40 x 30 Character mode: It uses 256 bytes per
line so total of 7,650 bytes.
SCREEN 2 – 80 x 60 Character mode: it also uses 256 bytes
per line for total 15,360 bytes ($3C00 HEX).
So for our purpose if we want to use one of these two text modes we can safely store sprite data anywhere after address $3C00, assuming we only use one layer.
Palette
This area of memory is used to define the available colors
for our sprites. We will use default 256 colors available to us and might look
into tricks that can be done with it in some future post.
Sprite Attributes
This is the most important part of the video memory related
to sprites. Commander X16 supports up to 128 hardware sprites. They all get
exactly 8 bytes to get their attributes defined and therefore occupy 1024 bytes
in memory area $1FC00 - $1FFFF:
Sprite 0: $1FC00
- $1FC07
Sprite 1: $1FC08
- $1FC0F
Sprite 2: $1FC10
- $1FC17
…
Sprite 127: $1FFF8
- $1FFFF
So what are the attributes?
Offset / Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
0 | Pointer to sprite graphics | |||||||
1 | Mode | Pointer to sprite graphics | ||||||
2 | X Position | |||||||
3 | X Position | |||||||
4 | Y Position | |||||||
5 | Y Position | |||||||
6 | Collision Mask | Z Depth | V-Flip | H-Flip | ||||
7 | Height | Width | Palette Offset |
We will use and therefore check in more detail the ones color coded in the picture above. Green ones are very straight forward, blue a bit more complicated and the red one is the trickiest and we will therefore spend most time on it.
Before we start…
One more thing before we start coding. As mentioned before
we will use VPOKE command to write to video memory and VPEEK to read from it.
Typically addresses in 8 bit computers are 16 bits and therefore have range
$0000 - $FFFF or 0 – 65535. Because VERA is using more than 64K we use
technique called banking or grouping the memory in 64K “banks”. But we don’t
need to worry about any of this because VPOKE takes care of it by adding an
extra parameter:
VPOKE bank, memory, value
Is used to write value into any valid location between
$00000 and $FFFFF. Of course when using bank $F we are not really addressing
memory but VERA registers. And actual Video RAM is only 16 KB so only banks $0
and $1 are valid without any memory expansions.
If we want to manipulate only certain bits inside byte we
can do that in Basic too.
VPOKE bank, memory,VPEEK(bank,memory) OR %1000000)
Will set bit 7 to 1 and leave all other values intact.
VPOKE bank,memory(VPEEK(bank,memory) AND %0111111)
Will clear bit 7 and leave all other values intact.
Turning Sprites on
Sprites can be turned on in two steps. First we set the
master enable flag on by setting bit 6 in the VERA Register DC_VIDEO ($9F29) to 1.
POKE $9F29,PEEK($9F29) OR %01000000
Next we can turn on individual sprites by setting Z-Depth
values for each one we want to display. If we check above Z-Depth is stored in
bits 2-3 at offset 6, so for Sprite 0 that would be $1FC06, Sprite 1 would be
$1FC0E and so on.
We need two bits because (as the name suggest) we control
not only on-off but also the depth in relation to screen layers. It has the
following possible values:
Value | Description |
---|---|
00 | Disabled |
01 | Between Background and Layer 0 |
10 | Between Layer 0 and Layer 1 |
11 | In front of Layer 1 |
Since the default text screen is rendered on Layer 1 we have to use the last value to display sprite on top. If you use graphics mode e.g. SCREEN $80 and put Sprite between Layer 0 and 1 you would see sprite behind the text and in front of background. You can try this later when we have something to display.
For now let’s just set it to front by:
VPOKE $1,$FC06,%00001100
Or if we want to only set those two bits
VPOKE $1,$FC06,VPEEK($1,$FC06) OR %00001100
The problem is that we still don’t see anything because we
haven’t defined any other attributes, position on screen and of course the
graphics of the sprite.
Sizing and Colors
Sprites can have 4 different sizes horizontally and
vertically and any combination of those. Just like for the depth we have two
bits to determine the size:
Value | Description |
---|---|
00 | 8 pixels |
01 | 16 pixels |
10 | 32 pixels |
11 | 64 pixels |
We set the dimensions in the upper four bits of the eighth byte of the Sprite attributes. Bits 6-7 for height and bits 4-5 for width. So for example if we want 8x8 sprite we set all four bits to 00. If we want sprite that 32 bits wide and 16 wide we set it to %0110.
Lower four bits are used for palette shifting by 16
positions every time one is added, which can be quite useful but we will not
explore it now, but feel free to experiment with it.
So, what are the colors that are at our disposal? By default
in first 16 position we have standard Commodore 64 colors, next 16 are
grayscale from black to white and the rest are different scales.
Only exception is color 0, which is always transparent and
it is the only color that is transparent.
Default Palette is described here.
The last thing about colors is to decide how many do we want to have in our sprite. We have two possibilities 16 or 256 and therefore we use either 4 bits per pixel or full byte per pixel. We set this in Mode setting – Bit 7 of Offset byte 1 with following values:
Default Palette is described here.
The last thing about colors is to decide how many do we want to have in our sprite. We have two possibilities 16 or 256 and therefore we use either 4 bits per pixel or full byte per pixel. We set this in Mode setting – Bit 7 of Offset byte 1 with following values:
0 – 4 bits per pixel
1 – 8 bits per pixel
Clearly we have to find the balance between how many colors
do we want to display per single sprite and how much space sprite occupies in
memory. At first glance it seems that 4 bits and only 16 colors are very
limited, however also in that case we have all 255 colors at our disposal and
using palette shifting each sprite can have access to different part of palette
if needed.
Positioning
We can position sprites anywhere on the screen. Since the
maximum screen resolution of Commander X16 is 640x480 we need at least 10 bits
to be able to store all values and that is exactly what we have.
In Offset byte 2 we store bits 0-7 of X (horizontal) coordinate
with remaining 2 high bits in Offset byte 3. Similarly we store Y (vertical)
coordinate in Offset byte 4 (bits 0-7) and Offset byte 5 (high bits).
If we have horizontal position in variable X, we could use
following commands to store position to correct registers for Sprite 0.
VPOKE $1,$FC02,X AND $FF
VPOKE $1,$FC03,INT(X/256)
Please not that in the current version of emulator position 0,0 is in the top left corner of the visible screen. It means that sprite can’t be drawn left or above the visible screen to allow for gradual entry into the visibility. I am assuming this might change in the future and this text will be updated accordingly.
We could consider Z-Plane as part of positioning in Z
coordinate too. We talked about different options in the section above.
Storing Appearance
Sprites are essentially small rectangular graphic areas and
we are already armed with all the information we need to understand the possibilities:
- Horizontal x vertical dimensions can be 8, 16, 32 or 64 pixels
- Each pixel can take 1 byte or half byte (4 bits)
- We understand the available colors in palette (and know where to change them if needed)
The only tricky part is to store the pointer to sprite
graphics into sprite registers because it is slightly unconventional. We are
used to round all addresses to full bytes or at least nibbles (4 bits or half
bytes) because that makes it convenient for displaying in hexadecimal notation.
However pointer to sprite graphics is 17 bits but we can only store 12 so lower
5 bits are always 0. That means we can point to memory locations in increments
of 32 bytes.
Video RAM is located from $00000 - $1FFFF – 16 KB, so
obviously with 17 bits long address we can reach all of it. We also already
determined that screen starts at $00000 and in default text mode (SCREEN 2) we
are safe anywhere after $03C00.
So how do we calculate the pointer?
OK, let’s assume we have our graphics data located from
$04000. In binary that is:
%0 0100 0000 0000 0000
If we cut away lower 5 bits we get:
%0 0100 0000 000
or properly grouped into nibbles and bytes:
10 0000 0000
Or in Hex:
$200
So all that remains is to write $00 to Offset 0 and $02 to Offset 1 (plus the Mode flag in the bit 7). I personally would prefer to have address shifted by 4 bits so it would be more clearly readable in Hex notation but I guess after a while one can get used to it.
Putting it all together
I think it is time to put all the knowledge together and use
it in practical example. Current version of the emulator has an interesting
feature built in, namely Sprite 0 is used to display mouse pointer. When mouse pointer is over the emulator
window it shows Sprite 0 at its location. By default the Sprites are off and
there is no graphics associated with it so nothing is shown but let’s define it
and turn it on so we see its position. By default it comes with plain black pointer but we can change that. First turn it on like this:
MOUSE 1
MOUSE 1
I think it is appropriate to use Amiga style pointer:
- We will therefore use 16 x 16 pixel sprite.
- We will use 256 color mode
- For Black we will use color index 16, for dark red index 50 (color $a22) and for pale red/tan index 38 (color $fbb).
- Since we did hard calculations above already, we will use $04000 to store the data. Here is the complete code:
To review..
In lines 20-50 we load 256 bytes of graphics data into Video
RAM from location $04000 on. Graphics data is stored in lines 1010 -1160, 16
bytes per line with colors 0 - transparent, 16 – black, 50 – dark red and 38 –
tan.
In line 110 we globally turn sprites on.
Line 120 sets the bits 5-12 of the pointer to graphics
($040000)
Line 130 sets the bits 13-16 of the same pointer plus it
sets the bit 7 to 1 to turn on 256 color sprite mode
Lines 140 – 170 set X and Y coordinates to top left corner
(0,0)
Line 180 sets Z-depth to 11, which means the sprite will be
on top of all other layers.
And finally in line 190 we set the sprite dimensions to 16 x
16 and leave the default palette offset.
This is really a very good introduction. Are you contributing to the documentation efforts for the Commander X16?
ReplyDeleteThank you Rob. I have been very busy lately so this post needs to be updated to be compatible with the latest version of Emulator. Hopefully I can get to it soon.
DeleteNo, I am not involved with the Commander X16 team but hopefully my instructions will be complementary to the official documentation.
Correction for line 110:
ReplyDelete110 POKE $9F29, PEEK($9F29) OR %01000000
Good catch, thanks. I corrected listing already. I guess I didn't update the whole program when I was updating to VERA 0.9.
Delete