Graphics Programming
Eric Ball Wrote (on AA)
You can't really think of the 7800 in terms of bitmaps like the Apple ][ or any other computer or console which uses a frame buffer for graphics. You certainly could allocate a chunk of RAM to use as a bitmap, set up some static display lists with entries pointing to the RAM, then have your program update the RAM like a frame buffer. Unfortunately, I think you'd find there isn't enough RAM or CPU time to do that method justice.
As Yoda says, "you must unlearn what you have learned."
7800 graphics data is stored as bytes, not pixels, with each byte representing 2 to 8 pixels depending on the graphics mode. The simplest two graphics modes are called 160A (2 bits/pixel, 160 pixels/line) and 320A (1 bit/pixel 320 pixels/line). The remaining four graphics modes don't have MSB to LSB = left to right bit to pixel mapping.
So say we want a 160A sprite which looks like a 4x4 pixel circle in 3 colors (to give a nice highlight):
0 1 2 0
1 1 3 2
1 1 1 1
0 1 1 0
which would translate to
DC.B %00011000, %01011110, %01010101, %00010100
Color = 0 translates to transparent or background (at least for 160A), assuming you have "Kangaroo Mode" turned off.
Well, not really. Due to how the 7800 handles graphics, the data is stored with each line on a separate page & upside down, thus:
ORG $F000
BALL
DC.B %00010100
ORG $F100
DC.B %01010101
ORG $F200
DC.B %01011110
ORG $F300
DC.B %00011000
Now, to display this in the center of the screen, you would create the following in RAM:
DLL
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 7, >DL0, <DL0
DC.B 4, >DL1, <DL1; num lines, display list pointer
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 16, >DL0, <DL0
DC.B 8, >DL0, <DL0
DL1
DC.B <BALL, 31, >BALL, 78; graphics pointer, 32-width, X-pos
DL0
DC.B 0,0; end of display list
For things like backgrounds there are a couple of options. The first is to store the background as a large sprite. The other is to use "character tiles", where the display list entry points to a series of bytes, which are then used as the LSB of the sprite pointer. This requires more DMA cycles, but uses less ROM. You can also easily update the tile list instead of the display list entries.