Sprites in Basic I - Setup


One of fundamental tools in the game developer's toolbox are hardware sprites and Commander X16 comes with a very strong and robust support. The hardware takes a big chunk of workload and makes Basic game programming even more feasible. However it can be quite confusing to start with and therefore in this short blog post I will explain how to configure sprites from Basic.
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:
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

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.


Link to Part II - Animation

Comments

  1. This is really a very good introduction. Are you contributing to the documentation efforts for the Commander X16?

    ReplyDelete
    Replies
    1. Thank 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.

      No, I am not involved with the Commander X16 team but hopefully my instructions will be complementary to the official documentation.

      Delete
  2. Correction for line 110:

    110 POKE $9F29, PEEK($9F29) OR %01000000

    ReplyDelete
    Replies
    1. 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

Post a Comment

Popular posts from this blog

Commander X16 Premium Keyboard