Figure 28 - At 240 by 240, graphics look much better with increase resolution
In the ball bouncing demo, a lot of the program memory (about 97 %) is used on the AVR644, and most of this is just data statements to define the 240 by 240 images. The full screen image takes up 57600 bytes of the 65535 bytes available, and the leftover is used for code! Of course, this demo is ultra basic, just bouncing a ball over the image and showing some text, so a lot more can be done with some creative coding. Games like PacMan, Space Invaders, or even some 3D demos would be no problem, for this system, with the real limiting factor being how many game sprites your can jam into the AVR program memory. Let's look at some of the basic subroutines and how they interact with the SRAM and the video rendering system.
The routine called PAGEFLIP found at "FLIP VIDEO PAGES" is probably the most important routine as it is called at the end of your main loop and is responsible for swapping the video buffers when all graphics have been drawn for the current frame. If your graphics routines are small and fast, then you should be able to pump out 60 frames per second. This PAGEFLIP routine will swap your buffers during the vertical blanking time and then return when it is safe to draw your next frame. If you are trying to draw something very complicated like a 3D game, then you may not be able to render 60 frames per second, so your frame rate will drop to the next lowest rate, such as 30FPS, 20 FPS, 15FPS, etc. Frame rates lower than 15FPS begin to look choppy, which means you are either exceeding this system's limits or have ugly inefficient code!
The two most used routines will be DRAWSPRITE at "COPY SPRITE TO SCREEN / SX=XLOC / SY=YLOC" and DRAWIMAGE at "COPY IMAGE TO SCREEN / SX=XLOC / SY=YLOC". Both of these routines move graphics stored in the program memory to the SRAM using the registers SX and SY to set the location on screen. DRAWSPRITE ignores bytes with the value zero to create a transparency color, whereas DRAWIMAGE just does a verbatim copy of date right to the screen. DRAWIMAGE is slightly faster as it does not have to worry about skipping invisible pixels. Again, these routines are just examples and could definitely be improved and modified to suit your needs.
I have also added a routine to wipe the entire video buffer called CLEARSCREEN at "CLEAR ENTIRE VIDEO SCREEN / PX=COLOR", and it just wipes out the entire 240 by 240 video buffer using the color value set in the register PX. This routine takes a lot of time, so you will probably only get 15FPS if you clear the screen at the beginning of each frame.
The routine called PRINTCHAR at "PRINT TEXT CHARACTER / T1=CHARACTER / SX=XLOC / SY=YLOC / PX=FORECOLOR / T2=BACKCOLOR" draws a single text character at the location set in the registers SX and SY. T1 represents one of the characters found in the table CHARS at "ALPHANUMERIC CHARACTER SET", and is a basic VGA character set. PX sets the foreground color and T2 sets the background color. IF PX and T2 are the same, then the background color is set to indivisible, drawing the character on the screen over top of whatever is already there.
The other routine called READPIXEL at "READ SCREEN PIXEL / SX=XLOC / SY=YLOC / RETURNS PX=COLOR" just returns the color value PX of the pixel at location SX and SY. This routine has been tested, but is not actually used in the ball bouncing demo.
Figure 29 - The ball bounce demo over two different image screens
To create the snake like effect as the ball bounces around, the previous ball sprite is not erased before drawing the next one at the new location. After some time, the ball will completely erase the image, leaving hundreds of balls on the screen. I know, the demo is lame considering what could be done with this project, but I will leave the bling to you! The text is drawn after the ball sprite, which is why the moving ball seems to move over top the text as it passes but the ball trail is behind. Graphics are layered this way by simply choosing the order in which they are draw to the buffer before it is flipped to the screen.
I know, a lot has been added to the new source code, and the demo programming is an ugly hack, so here is a stripped down empty framework that has only the video rendering interrupt and graphics routines remaining so you can create your own games and demos from the code. Feel free to alter any of the routines, but be careful not to mess around with the actual video driver or you may end up with no video at all. Anything after "VIDEO RENDERING INTERRUPT / R2=SOUND FREQUENCY / RETURNS R25=MEMREADY" should not be changed unless you have a real handle on all of this crazy video timing madness! Also, don't change "STARTUP SEQUENCE" unless you know what effect this will have on the rest of the code.
< Here is the blank video driver framework source code >
This empty code framework does all of the complex VGA timing in the interrupt and lets you write your own demos, games and applications in the "MAIN PROGRAM LOOP". The routines used to make the previous demo are also included, and they are easy to figure out by looking at the comment headers to see which registers they use or return. The main loop is basically empty except for the few lines that first clear the entire screen and then flip the video buffers, although you may want to do something different there as well. Remember, the CLEARSCREEN routine takes more than a full frame, so it may not be the best way to pump out frames on a fast moving game. It may be more advantageous to only alter the parts of the screen that are moving, leaving the background intact during each frame. PacMan would be a good example of this, drawing the maze first and then only moving the small player sprites around.
Also included in the basic framework are the routines to draw text (PRINTCHAR), sprites (DRAWSPRITE), images (DRAWIMAGE), and read pixels (READPIXEL). A sinus lookup table has also been added as this is almost always useful in graphics demos and games. If you would like to add joystick support, just drop in another 74HC245 or 74HC244 and control the OE pin using PORT B.6. The output from the buffer is fed into the data bus and read in the same way the READPIXEL routine works.