P/M Graphics Made Easy
T. Sak, S. Meier
Many people have called the Atari's graphics capabilities its best feature, especially the player-missile graphics. We won't argue, but how many of you have backed away because it looks too difficult to handle in BASIC or you simply are not satisified with the execution speeds which you are able to achieve?
Well, no more excuses! We've got a machine language subroutine that you can use with BASIC to achieve exciting graphics performance without a lot of muss and fuss. As a matter of fact, you make only one setup call to the subroutine and then forget it! And we promise you need know nothing about machine language. Just a few POKEs and you'll have your players dancing around the television screen.
You Don't Need To Know Machine Language
There have been a number of very helpful articles published describing the essential player-missile graphic information. Chris Crawford's description in COMPUTE! #8 is particularly noteworthy. We're going to assume that you are familiar with the fundamentals, but we'll review highlights as they're required.
A feature of the Atari with which you may not be familiar is its "interrupt" mechanism and how you can let it move your players for you at machine language speed — without the overhead of calling it from your BASIC program. Before we explore this useful feature, let's take a quick refresher course on interrupts.
As you know, the Atari keeps itself pretty busy doing its "housekeeping" chores even while it is interpreting your BASIC program. Among other things, the Atari must maintain the steady delivery of information to your television set, allowing it to paint a constantly up-to-date picture of the display data. Multiple, concurrent activities are performed by allowing one particular activity to periodically interrupt another.
The traditional analogy is that of a busy business executive who, while engaged in a meeting with an associate, is interrupted by a telephone call. The ringing phone signals the interrupt; the executive "checkpoints" his meeting and answers the phone. After disposing of the call, the executive resumes his meeting at the point of interruption.
A similar circumstance occurs each time a complete picture is painted by your television set. The television's electron beam paints the picture by sweeping horizontal rows across the picture tube beginning in the upper left hand corner and ending in the lower right. The beam is turned off when it reaches the lower right corner and is returned to its upper left starting position. This return trip is essentially a vertical positioning movement so this period when the beam is turned off is known as the vertical blank time.
Move During Vertical Blanks
The onset of the vertical blank cycle serves as an opportunity for the Atari's antic chip to signal an interrupt, the vertical blank or VBLANK interrupt. The operating system uses this occasion to perform some of its "housekeeping" duties. Fortunately, the operating system designers allow us to include a machine language subroutine which can be executed as one of these tasks.
The machine language vertical blank interrupt player movement subroutine described here is called VBLANK PM and it allows you to simply POKE the next x and y coordinate at which your player is to be displayed. There is no need to repeatedly call the subroutine from BASIC via the USR function. The subroutine will be automatically executed during the next vertical blank period. It is possible to move the players every time a new screen is painted on the television—and that's 60 times a second!
You may recall from other articles that an appropriate POKE to location 53248 (and the three memory locations following) permits you to position players zero through three horizontally along the x-axis. It's not quite as easy to position the players vertically along the y-axis. Not until now!
The VBLANK PM subroutine takes care to move the players in both directions. Movements along the vertical axis involve "erasing" and rewriting the player in the new position. VBLANK PM does this for you, automatically. There are a few things which you must do for VBLANK PM however.
First, you must get the VBLANK PM machine language subroutine into memory and notify the operating system that is to be included as one of the "housekeeping" tasks to be performed as a part of servicing the vertical blank interrupt. Next, it's up to you to draw your players and tell VBLANK PM how tall they are. After initialization, VBLANK PM looks after the positioning of your players until either a warm start (pressing SYSTEM RESET) or a cold start (power-off, power-on sequence) is performed.
Program 1 is an example of the initialization and use of the VBLANK PM subroutine. This program causes VBLANK PM to be loaded and initialized and players zero and one to be drawn and then moved about the television screen in a random pattern. The players are male and female gender symbols which the program "dances" around the screen.
Lines 100 through 200 are the main program; we'll save an explanation of these lines until after you've gained some insight into the initialization subprogram contained in lines 1000 through 1110. The VBLANK PM machine language subroutine is expressed in the DATA statements numbered 2000 through 2100. Finally, lines 3000 through 3020 supply a description of the two players used in this example.
The first task is to load VBLANK PM into page six of memory. Page six is locations 1536 through 1791 (hexadecimal 600 through 6FF) and has been left available by Atari's software designers for applications such as this one. These 256 bytes of memory are not disturbed by BASIC or DOS; however, a cold start does cause page six to be cleared to zeroes. Line 1010 causes the VBLANK PM to be read and POKEd into memory. Line 1020 clears a few locations used by the subroutine; this statement can be omitted if you are sure that page six has not been altered since the last cold start.
We're going to employ the Atari's antic chip direct memory access (DMA) facility to transfer graphics information from memory to the television using single line resolution. (You might want to reread Chris Crawford's article or just "trust us on this one!") This means that we must allocate 2K (2048) bytes of memory for the storage of players. In line 1030 we obtain the page number of RAM-TOP, deduct 16 pages, and call the result the base of the required 2K byte allocation.
Why 16 pages? Well, first consider that 2K bytes are eight pages (a page contains 256 bytes) and that, depending on the graphics mode (i.e., GRAPHICS 0 through GRAPHICS 8), you must allow sufficient space at the top of RAM to contain the display list and screen data. Incidentally, the player-missile 2K byte allocation must begin at an address which is a multiple of 2048; we call this starting address PMBASE.
One more cautionary note: you will have to allow more than 16 pages between PMBASE and RAMTOP if you are using graphics modes six through eight. Fred Pinho's article in COMPUTE! #16 provides greater detail in this area.
Figure 1 depicts the 2K byte memory allocation. Remember, we didn't design this scheme, Atari did, and we're not sure why but there is a considerable amount of unused space involved. You can use the lower, unused bytes for your own purposes without disturbing anything, if you like. We're only going to use the upper 1K bytes.Figure 1.
Player zero occupies PMBASE + 1024 through PMBASE + 1279; player one is situated in locations PMBASE + 1280 through PMBASE + 1535, and so on for players two and three. Line 1040 clears any residual data — if you're in a hurry and are sure that this area is already clear (i.e., following a cold start), you won't need line 1040.
Lines 1050 and 1060 are used to draw players zero and one. VBLANK PM expects the players to be drawn such that their top line is initially placed at the beginning of the individual player's storage area. The player can be as tall as you like up to 255 lines; of course, you will never see all of a player which is that tall on the screen at the same time!
Next you can see that we've taken advantage of the Atari's special memory locations for some functions. You establish the players' colors with a POKE into locations 704 through 707 for players zero through three, respectively. Line 1070 is used to set the colors and assumes that you've set the variables PCOL0, PCOL1, PCOL2, and PCOL3 already.
Line 1080 establishes the positioning addresses which you will be using later to signal player movements using only POKEs. PLX and PLY are the locations POKEd to establish the next x and y position of player zero. A POKE into location PLX + 1 and PLY + 1 accomplishes the same thing for player one, and so forth for players two and three. PLL (and PLL + 1, PLL + 2, and PLL + 3) are POKEd to inform VBLANK PM of the length (or height) of each player.
Line 1090 initializes the remaining control parameters. A 62 is POKEd into location 559 to set the single line player-missile resolution graphics; a one placed into location 623 establishes the player/playfield priorities giving the players priority over the playfield. (You can change this to suit your purposes, if you wish.) Location 1788 is in VBLANK PM and is POKEd with the number of the first page containing player-missile data. Locations 53277 and 54279 are used to switch on the DMA graphics data transfer facility and to tell the ANTIC chip where in memory to find the player graphics data.
Wrapping Up The Loose Ends
You're almost ready to go! A subroutine call to VBLANK PM from line 1100 allows VBLANK PM to notify the operating system of both his presence and his desire to be automatically invoked as a part of the vertical blank interrupt process. This is the only time in which your BASIC program must explicitly call VBLANK PM.
Okay, to wrap up loose ends, let's take a quick look at the main program—lines 100 through 200. Line 100 turns off the cursor, clears the screen, and provides a black background so that we can readily see the players.
Line 110 sets the players' colors before the VBLANK PM initialization subprogram is executed. You know how to set the colors, right? Multiply the color number by 16 and add the desired intensity—the color and intensity numbers are the same as those used in the SETCOLOR command. Line 120 assures the VBLANK PM is launched.
Line 130 illustrates the manner in which you pass instructions to VBLANK PM. Here we are telling VBLANK PM that both players are eight lines tall. You can change this parameter at any time—we have a little surprise for you later about why you might want to change this parameter.
Lines 140 and 150 establish the initial television screen positions of players zero and one, respectively. A word about the available values for the x and y coordinates might be helpful as not all x and y values will result in the player being displayed. There are 255 x positions with only 160 of these appearing across the television screen beginning with an x value of 48.
Similarly, there are 255 y positions with 192 of these visible on the screen beginning with 32 at the top. (These x and y values may vary slightly depending on the adjustment of your television receiver.) VBLANK PM assumes that you are referring to the upper left hand corner of your player whenever you POKE new x and y coordinate values.
Lines 170 and 180 illustrate the use of the pseudo-random number function to determine the next set of x and y coordinates. Line 190 provides a small delay between player movements. Delete the FOR and NEXT statements if you want to see how fast — and easy — it is to move players.
Well who said player-missile graphics had to be anything but fun?! Give VBLANK PM a try in one of your current programs to add a little zip; or try it in your next graphics project.
Oh, we almost forgot that we promised you a surprise regarding why you might want to change the height of a player. VBLANK PM has a few more features which allow you to animate the movements of your players — but more about this next time!
100 POKE 7521 1 : PRINT CHR$(125) : SETCOLOR 2, 0, 0 110 PCOL0 = 216 : PCOL1 = 56 : REM color of players 120 GOSUB 1000 : REM initialize vb routine 130 POKE PLL, 8 : POKE PLL + 1, 8 : REM player's height 140 POKE PLX, 108 : POKE PLY, 102 : REM player 0's initial position 150 POKE PLX + 1, 108 : POKE PLY + 1, 72 : REM ditto player 1 160 REM let players dance! 170 POKE PLX, RND(0)*159 + 48 : POKE PLY, RND(0)*191 + 32 180 POKE PLX + 1, RND(0)*159 + 48 : POKE PLY + 1, RND(0)* 191 + 32 190 FOR I = 1 TO 75 : NEXT I : GOTO 170 200 END 1000 REM INITIALIZE VBLANK PM SUBR 1010 FOR I = 1536 TO 1706 : READ A : POKE I, A : NEXT I 1020 FOR I = 1774 TO 1787 : POKE I, 0 : NEXT I 1030 PM = PEEK(106)-16 : PMBASE = 256*PM 1040 FOR I = PMBASE + 1023 TO PMBASE + 2047 : POKE I, 0 : NEXT I 1050 FOR I = PMBASE + 1025 TO PMBASE + 1032 : READ A : POKE I, A : NEXT I 1060 FOR I = PMBASE + 1281 TO PMBASE + 1288 : READ A : POKE I, A : NEXT I 1070 POKE 704, PCOL0 : POKE 705, PC0L1 : POKE 706, PCOL2 : POKE 707, PCOL3 1080 PLX = 53248 : PLY = 1780 : PLL = 1784 1090 POKE 559, 62 : POKE 623, 1 : POKE 1788, PM +4 : POKE 53277, 3 : POKE 54279, PM 1100 X = USR(1696) 1110 RETURN 2000 REM vblank interupt routine 2010 DATA 162, 3, 189, 244, 6, 240, 89, 56, 221, 240, 6, 240, 83, 141, 254, 6, 106, 141 2020 DATA 255, 6, 142, 253, 6, 24, 169, 0, 109, 253, 6, 24, 109, 252, 6, 133, 204, 133 2030 DATA 206, 189, 240, 6, 133, 203, 173, 254, 6, 133, 205, 189, 248, 6, 170, 232, 46, 255 2040 DATA 6, 144, 16, 168, 177, 203, 145, 205, 169, 0, 145, 203, 136, 202, 208, 244, 76, 87 2050 DATA 6, 160, 0, 177, 203, 145, 205, 169, 0, 145, 203, 200, 202, 208, 244, 174, 253, 6 2060 DATA 173, 254, 6, 157, 240, 6, 189, 236, 6, 240, 48, 133, 203, 24, 138, 141, 253, 6 2070 DATA 109, 235, 6, 133, 204, 24, 173, 253, 6, 109, 252, 6, 133, 206, 189, 240, 6, 133 2080 DATA 205, 189, 248, 6, 170, 160, 0, 177, 203, 145, 205, 200, 202, 208, 248, 174, 253, 6 2090 DATA 169, 0, 157, 236, 6, 202, 48, 3, 76, 2, 6, 76, 98, 228, 0, 0, 104, 169 2100 DATA 7, 162, 6, 160, 0, 32, 92, 228, 96 3000 REM players 0 & 1 3010 DATA 6, 6, 8, 126, 195, 195, 195, 126 3020 DATA 126, 195, 195, 126, 24, 126, 126, 24