Classic Computer Magazine Archive COMPUTE! ISSUE 37 / JUNE 1983 / PAGE 226

Custom Characters
On Atari
Charles Delp

Custom character graphics is an easy way to program game animation, but sometimes it results in uneven motion. Smoother animation can be achieved by using custom characters to create the fixed playfield, and then using player/missile graphics to animate the players. The three programs here show you how.

One of the easiest ways to put colorful, high resolution playfields or special symbols on the screen is with character graphics, employing custom characters. A good example of custom character graphics is demonstrated by the game Gold Miner (COMPUTE!, July 1982).
    Gold Miner also demonstrates one of the major drawbacks of using character graphics to animate a game: players can move only in large, character-sized jumps. When smoother action is desired, a better solution is to draw the fixed playfields using custom characters and then animate the players using player/missile graphics.
    The advantages of using character graphics rather than bit mapped graphics to draw fixed playfields are:

1. Much less memory is required to achieve the same resolution.
2. More colors are available.
3. Less time is required to draw to screen memory.
4. Color fill is faster and easier.

    The major disadvantage of using character graphics to draw fixed playfields is that only two colors (character color and background color) are available within any one character. Figure 1 shows the resolution, memory requirements, and colors available for various Atari BASIC character and bit mapped graphics modes.

How Characters Are Defined
Atari characters are defined by 64 pixels arranged in eight columns by eight rows. From right to left, the values of the columns are 1, 2, 4, 8, 16, 32, 64 and 128. If a particular pixel is turned on, the value of that column is added to the row total; if the pixel is turned off, zero is added to the row total. The total value of all the "on" pixels in a row forms a byte of data which defines that row. Each of the eight rows is defined by a byte of data, for a total of eight bytes per character. (See Figure 2 for a specific example.) Note how the row bytes are arranged in memory from the character start address (CHADD).

Character Editor
Program 1 is a character editor utility which will be a help in developing the DATA statements required to define each character. Draw the character using the joystick. Erase errors by holding the trigger button while drawing over the error. Press C (Clear character) at any time to clear the screen for another character. Press D (Demonstrate character) to see the character in all three of the character graphics modes, as well as the DATA statement required to produce the character. Press P (Print data) to print a hard copy of the character DATA statement. Press E (Enter data) to enter the character data as a program line beginning at line 9000. When all characters have been entered, typing LIST"D: CHAR", 9000,9999 will save the data to disk or LIST"C",9000,9999, to cassette. The data may be merged into your graphics program using the ENTER command (see chapter 5, Atari Basic Reference Manual).

Locating The Custom Character Set In Memory
First, look at the memory map in Figure 3. The standard Atari character set is located in ROM beginning at address 57344 (CHORG). The location and size of screen memory including the display list will depend on how much RAM is installed in your computer and which graphics mode is called by your program. The new character set must be defined and stored in RAM in a location which does not interfere with screen memory, the display list, the player/missile display memory, or the BASIC program. The procedure described below and illustrated in Figure 3 will keep everything nicely separated.

1. Find MEMTOP on your computer by entering the following line: PRINT PEEK (106)*256.
2. Decide whether your program using the custom characters will be written in graphics mode 0, 1, or 2. For your information, the bottom of screen memory, including display list, will be located at MEMTOP - X
    where X = 992 for graphics mode 0
              X = 674 for graphics mode 1
              X = 424 for graphics mode 2
3. The starting address of the custom character set, CHBASE, must be located on a 1K memory boundary, so CHBASE should start 2K below MEMTOP (1K for screen memory, 1K for the character set); therefore, CHBASE = MEMTOP - 2048.
4. If player/missile graphics are to be used, PMBASE must be located on a 2K boundary (for single line resolution), so P/M Base should start 4K below MEMTOP (1K for screen memory, 1K for the character set, 2K for P/M Display Area); therefore, PM BASE = MEMTOP - 4096.

Developing A Custom Character Set
Normally a character set consists of 128 different characters in graphics mode 0, and 64 different characters in graphics modes 1 and 2. However, a character set need not be full and may contain only as many characters as needed to meet the requirements of your program. The first character in the set must always be a space (DATA statement filled with zeros).
    Program 2 demonstrates how to set up and use a custom character set containing only custom characters. To keep things simple, the set contains only eight characters.

Lines 10-30 Initialize and find CHBASE
Lines 50-70 Clear space in memory for the custom character set
Lines 90-130 POKE the new characters into memory beginning at CHBASE
Lines 200-280 Contain the character data
Lines 300-360 Print the characters on the screen

    The simplest way to print the custom characters to the screen is with the PRINT #6 statement; however, the custom characters are not shown on the keyboard, so the following correlation must be performed:

Note: Refer to Table 9.6 - The Internal Character Set, in the Atari BASIC Reference Manual, page 55.

1. Assign a character number to each of your custom characters, beginning with zero for your first character, number 1 for your second character, number 2 for your third character, etc.
2. Correlate your character numbers, one for one, with the Atari internal character set numbers in Table 9.6.
3. To print your custom character, enter the corresponding Atari character in your print statement. For example, the Atari character number 4 is the dollar sign ($). PRINT #6; "$" will print your custom character number 4 on the screen.

    It is necessary to skip the third character of your set. (See line 220 of Program 2.) The third character corresponds to the Atari internal character quotation mark ("). It is not possible to print a quotation mark to screen using the PRINT #6 statement.
    The color of a character is selected by its form in the print statement. If the custom character corresponds to an Atari alphabetical letter, the color is determined by entering the corresponding Atari letter in the print statement in upper- or lowercase, or inverse upper- or lowercase. Four colors are available for characters corresponding to Atari alphabetical letters.
    If the custom character corresponds to an Atari number, punctuation mark, etc., the color is determined by entering the corresponding Atari number in the print statement in standard or inverse video. No upper- or lowercase numbers and punctuation marks are possible, so only two colors are available for these characters when using the PRINT #6 method. (See the table for character color information.)
    The PRINT #6 method of putting custom characters on the screen has some serious drawbacks. The method used in Program 3 may not be as easy to understand, but has fewer limitations, particularly for drawing entire playfields.

Mixing Standard And Custom Characters
In addition to colorful playfields, most games print numbers and specific letters on the screen to display such things as score, time, fuel, hits, etc. The standard Atari character set already contains these characters, so it would be pointless to develop custom characters for this purpose. The solution is to develop a custom character set containing all the necessary standard numbers and letters, but to replace all unneeded standard characters with custom characters.
The procedure for developing a mixed character set is described below:

Note: Refer to Table 9.6 in the Atari BASIC Reference Manual, page 55.

1. Determine which standard characters will be needed in your program.
2. Form a string variable which contains the unneeded standard characters. The string may include any unneeded characters with numbers between zero and 127 for graphics 0, or between zero and 63 for graphics 1 and 2. The only exception in either case is the quotation mark, for reasons explained before. (Try putting a quotation mark in your string.) An example string:
CHNEW$="!#*<BFGJLMPQZ "
3. Copy the standard character set from CHORG (57344) to CHBASE by PEEK and POKE statements.
4. Modify the unneeded standard characters into custom characters by POKEing custom character data into the character address (CHADD) of each character in the string. (See Program 3 for specific details of the procedure.)

Printing Complete Playfields
Program 2 places the custom characters on screen with PRINT #6 statements. A better, though more difficult, method is plotting the character on the screen using color data to designate which character is to be plotted and in what color the character will appear. The color data to define a character contains two elements: the character number (the Atari internal character set number from table 9.6), and a plus or minus offset which determines the color of the character. The offsets may be obtained from Figure 9.7 on page 56 of the Atari BASIC Reference Manual. The easiest way to explain this concept is with examples.

Example 1: Suppose you want to display the standard character "K" in Graphics mode 1 with color 0:

1. From table 9.6, the internal character number for "K" is 43. Note that the "K" is from column 2.

2. From table 9.7, the offset to produce a column 2 character in color 0 is + 32.

3. The color data to plot "K" in color 0 would be 43+32=75.

4.210 ...
   220 Color 75
   230 Plot 5,7
   240 ...
    The program lines above will print a "K" in color 0 at X = 5, Y=7.

Example 2: Suppose you want to display your custom character number 19 in graphics mode 2 with color 3. Your character number 19 corresponds to the standard character ";":
1. From table 9.6, the internal character number for ";" is 27 from column 1.
2. From table 9.7, the offset to produce a column 1 character in color 3 is + 128.
3. The color data to plot your custom character in color 3 would be 27 + 128 =155.
4.150 ...
   160 Color 155
   170 Plot 7,1
   180 ...
    The program lines above will print your custom character in color 3. at X = 7, Y =1.
    A complete playfield may be drawn using the color/plot method by implementing a nested row, column loop which reads the color numbers from DATA statements and plots the characters to the screen (see lines 550 through 610 of Program 3 for a method).

    Program 3 is a full screen, graphics 2, fixed playfield demonstration using 31 custom characters:

Lines 30-80 Initialize, define string, and find CHBASE.
Lines 110-130 Move standard character set down to CHBASE.
Lines 150-210 Modify the characters in the string into custom characters. Line 160 locates the correct addresses to modify. The -32 is an offset to change ATASCII to Atari internal character numbers.
Lines 301-331 Custom character data.
Line 420
Select split screen mode; kill cursor.
Line 510-530 Change character set pointer; select colors.
Lines 550-610 Read color data and plot characters on screen.
Line 630 Print standard characters in text window.
Lines 650-680 Flicker engine exhaust.
Lines 700-709 Color data for ten rows of 20 characters.

Figure 1: Atari Display Mode Facts
 

Graphics
  Mode 
 
 
Graphics
  Type
 
 
Resolution
  HxV 
Colors
Available
(including
Background)
 
Bytes of
Memory/
  Screen 
0
Character
 320x192
2
  960
1
Character   160x192
5
  480
2
Character  160x96
5
  240
5
Bit Mapped
   80x48
4
  960
7
Bit Mapped  160x96
4
3840
8
Bit Mapped  320x192
2
7680

Character Color Information
Character Type Color Register
Uppercase alphabetical 0
Lowercase alphabetical 1
Inverse uppercase alphabetical 2
Inverse lowercase alphabetical  3
Numbers, punctuation marks, etc,  0
Inverse numbers, punctuation marks, etc, 2


Figure 2:

Figure 3:


Program 1: Character Editor

5 CLR :? "{CLEAR}":OPEN #1,4,0,"K:":
  OPEN #6,4,0,"S:":SETCOLOR 2,9,2:SE
  TCOLOR 4,9,2:POKE 752,1
10 DIM C$(1),STORE(8):N=0
20 GOSUB 6000
40 ? :? :? "PLUG JOYSTICK INTO JACK
   1"
50 ? "DRAW CHARACTER WITH JOYSTICK"
60 ? "HOLD TRIGGER BUTTON TO ERASE":
   ? :?
70 ? :? :? "{8 SPACES}PLEASE WAIT .
   . ."
90 CHBASE=(PEEK(106)-8)*256:CHORG=57
   344
100 FOR I=0 TO 1023:POKE CHBASE+I,PE
    EK(CHORG+I):NEXT I
105 C$="&"
110 CHADD=CHBASE+(ASC(C$)-32)*8
120 POKE 756,CHBASE/256
200 ? "{CLEAR}":POKE 752,1:GOSUB 600
    0
205 FOR I=0 TO 7:STORE(I)=0:NEXT I
210 ?
210 ? "{5 SPACES}87654321"
230 ? "{4 SPACES}{Q}{8 R}{E}"
240 ? "{4 SPACES}:{8 SPACES}: 1"
250 ? "{4 SPACES}:{8 SPACES}: 2"
260 ? "{4 SPACES}:{8 SPACES}: 3"
    {3 SPACES}C = CLEAR CHAR"
270 ? "{4 SPACES}:{8 SPACES}: 4
    {3 SPACES}D = DEMO CHAR"
280 ? "{4 SPACES}:{8 SPACES}: 5
    {3 SPACES}P = PRINT DATA"
290 ? "{4 SPACES}:{8 SPACES}: 6
    {3 SPACES}E = ENTER DATA"
300 ? "{4 SPACES}:{8 SPACES}: 7"
310 ? "{4 SPACES}:{8 SPACES}: 8"
320 ? "{4 SPACES}{Z}{8 R}{C}"
499 REM MAIN LOOP
500 X=7:Y=6
510 K=PEEK(764)
512 IF STRIG(0)=0 THEN 700
513 IF K=18 THEN 1000
514 IF K=58 THEN 2000
515 IF K=10 THEN 3000
516 IF K=42 THEN 5000
518 POSITION X,Y:? " "
520 FOR DELAY=1 TO 15:NEXT DELAY
530 POSITION X,Y:? ""
540 FOR DELAY=1 TO 15:NEXT DELAY
550 ST=STICK(0)
560 IF ST=15 THEN 510
570 IF ST=6 OR ST=14 OR ST=10 THEN Y
    =Y-1
580 IF ST=5 OR ST=9 OR ST=13 THEN Y=
    Y+1
590 IF ST=5 OR ST=6 OR ST=7 THEN X=X
    +1
600 IF ST=9 OR ST=10 OR ST=11 THEN X
    =X-1
610 IF X>14 THEN X=14
620 IF X<7 THEN X=7
630 IF Y>13 THEN Y=13
640 IF Y<6 THEN Y=6
650 GOTO 510
700 POSITION X,Y:? ""
710 FOR DELAY=1 TO 15:NEXT DELAY
720 POSITION X,Y:? " "
730 FOR DELAY=1 TO 15:NEXT DELAY
732 IF K=18 THEN 1000
734 IF K=58 THEN 2000
736 IF K=10 THEN 3000
738 IF K=42 THEN 5000
740 GOTO 550
999 REM CLEAR CHAR
1000 POKE 764,255
1010 GOTO 200
1999 REM DEMO CHAR
2000 BYTE=0:BIT=0
2005 GOSUB 4000
2008 REM DETERMINE DATA VALUES
2010 FOR Y=0 TO 7
2020 FOR X=7 TO 0 STEP -1
2030 LOCATE (X+7),(Y+6),PIX
2035 POSITION (X+7),(Y+6):PUT #6,PIX
2040 IF FIX=160 THEN PIX=1
2050 IF PIX=32 THEN PIX=0
2060 IF X=7 THEN BIT=PIX
2070 IF X=6 THEN BIT=PIX*2
2080 IF X=5 THEN PIT=PIX*4
2090 IF X=4 THEN BIT=PIX*8
2100 IF X=3 THEN BIT=PIX*16
2110 IF X=2 THEN BIT=PIX*32
2120 IF X=1 THEN BIT=PIX*64
2130 IF X=0 THEN BIT=PIX*128
2140 BYTE=BYTE+BIT
2150 NEXT X
2160 STORE(Y)=BYTE
2165 BYTE=0
2170 NEXT Y
2180 POSITION 2,16:? "DATA ";
2190 FOR Y=0 TO 6
2200 STORE=STORE(Y)
2210 ? STORE;",";
2220 NEXT Y
2230 STORE=STORE(7)
2240 ? STORE;
2242 FOR J=0 TO 7:STORE=STORE(J)
2244 POKE CHADD+J,STORE:NEXT J
2248 REM ALTER DISPLAY LIST
2250 A=PEEK(560)+PEEK(561)*256
2260 POKE A+25,6:POKE A+26,6:POKE A+
     27,7:POKE A+28,PEEK(A+29):POKE
     A+29,PEEK(A+30):POKE A+30,PEEK(
     A+31)
2265 REM PRINT CHAR TO SCREEN
2270 POSITION 2,18:? "{3 SPACES}GR 0
     :  & & & & & & & & & & & & &";
2280 POSITION 0,20:? #6;"GR 1: & & &
      & & & &";
2290 POSITION 0,21:? #6;"GR 2: & & &
      & & & &";
2345 POKE 764,255
2350 GOTO 500
2999 REM PRINT DATA TO PRINTER
3000 TRAP 3100
3005 POKE 559,0
3030 GOSUB 3200
3040 LPRINT "DATA ";S0;",";S1;"'";S2
     ;",";S3;",";S4;",";S5;","S6;",
     ";S7
3050 POKE 559,34
3060 POKE 764,255
3070 GOTO 200,
3100 GOSUB 4000
3110 POKE 559,34
3120 POSITION 2,17
3130 ? " PRINTER NOT CONNECTED"
3140 ? "{9 SPACES}- OR -"
3150 ?    "{3 SPACES}PRINTER TURNED OFF"
3160 FOR DELAY=1 TO 400:NEXT DELAY
3165 GOSUB 4000
3170 POKE 764,255
3180 GOTO 200,
3200 S0=STORE(0):S1=STORE(1):S2=STOR
     E(2):S3=STORE(3):S4=STORE(4):S5
     =STORE(5):S6=STORE(6):S7=STORE(
     7)
3210 RETURN
3999 REM CLEAR DATA SUB
4000 POSITION 2,16
4010 FOR Y=16 TO 19
4020 ? "{37 SPACES}"
4030 NEXT Y
4040 POSITION 0,20:? "{19 SPACES}"
4050 POSITION 0,21:? "{19 SPACES}"
4200 RETURN
4999 REM ENTER DATA INTO PROGRAM
5000 POKE 559,0
5010 GOSUB 3200
5020 GOSUB 5200
5030 ? 9000+N;" DATA ";S0:",";Sl;","
     ;S2;".";S3;",";S4;",";S5;",";S6
     ;",";S7
5040 GOSUB 5210
5050 N=N+1
5060 POKE 764,255
5070 POKE 559,34
5080 GOTO 200
5200 ? CHR$(125):? :RETURN
5210 ? :? :? "CONT":POSITION 0,0:PO"
     E 842,13:STOP
5220 POKE 842,12:? CHR$(125):? :RETU
     RN
6000 ? "{10 SPACES}CHARACTER EDITOR"
6010 ? "{10 SPACES}{16 M}"
6020 RETURN


Program 2: Custom Characters

10 N=0
20 MEMTOP=PEEK(106)*256
30 CHBASE=MEMTOP-2048
40 REM CLEAR MEMORY FOR NEW CHARACTE
   R SET
50 FOR I=CHBASE TO CHBASE+1024
60 POKE I,0
70 NEXT I
80 REM POKE NEW CHARACTER SET INTO M
   EMORY
90 READ A
100 IF A=999 THEN 300:REM 999 IS END
     OF DATA FLAG
110 POKE CHBASE+N,A
120 N=N+1
130 GOTO 90
190 REM DATA STATEMENTS FOR SPACE,6
    CHARACTERS AND FLAG, FIRST CHARA
    CTER MUST BE A SPACE
195 REM LINE 220 IS A SPACE TO SKIP
    THE QUOTATION MARKS
200 DATA 0,0,0,0,0,0,0,0
210 DATA 32,33,35,35,35,35,255,255
220 DATA 0,0,0,0,0,0,0,0
230 DATA 112,112,112,112,248,248,248
    ,248
240 DATA 248,252,254,254,86,6,255,25
    5
250 DATA 0,0,32,32,32,32,112,240
260 DATA 41,38,32,32,32,32,32,32
270 DATA 0,0,0,0,0,32,32,48
280 DATA 999
290 REM SET GRAPHICS MODE
300 GRAPHICS 2
310 REM TELL COMPUTER WHERE TO FIND
    NEW CHARACTER SET
320 POKE 756,CHBASE/256
324 REM PRINT NEW CHARACTERS
325 POSITION 9,7
330 ? #6;"'%"
335 POSITION 9,8
340 ? #6;"&#"
345 POSITION 9,9
350 ? #6"!$"
360 GOTO 360


Program 3: Fixed Playfield Demonstration

10 CLR
20 REM N = NUMBER OF CHARACTERS IN C
   HNEW$ STRING
30 N=31:CHORG=57344
40 REM DEFINE STRING
50 DIM CHNEW$(N)
60 CHNEW$="!#$Y,&'()#+,-,/;<=>?@BGHJK
   MNPQVW"
70 REM FIND CHBASE
80 CHBASE=(PEEK(106)-8)*256
90 ? :? " PLEASE WAIT, 760 NUMBERS
   TO MOVE"
100 REM COPY STANDARD CHARACTER SET
    FROM CHORD TO CHBASE
110 FOR I=0 TO 511
120 POKE CHBASE+I,PEEK(CHORG+I)
130 NEXT I
140 REM READ AND POKE CUSTOM DATA IN
    TO THE CHARACTERS IN STRING CHNE
    W$"
150 FOR I=1 TO N
160 CHADD=CHBASE+(ASC(CHNEW$(I))-32)
    *8
170 FOR J=0 TO 7
180 READ A
190 POKE CHADD+J,A
200 NEXT J
210 NEXT I
300 REM CUSTOM CHARACTER DATA
301 DATA 0,0,0,128,0,0,0,0
302 DATA 0,0,0,0,0,050,16
303 DATA 0,0,0,0,1,0,0,0
304 DATA 8,0,0,0,0,0,0,0
305 DATA 0,0,0,0,0,0,31,127
306 DATA 0,0,0,0,0,0,255,255

307 DATA 0,0,0,0,0,0,248,254
308 DATA 0,0,0,0,7,15,31,31
309 DATA 1,7,31,24,255,255,255,219
310 DATA 255,231,255,0,255,255,255,2
    19
311 DATA 128,224,248,24,255,255,255,
    219
312 DATA 0,0,0,0,224,240,248,248
313 DATA 31,31,15,7,1,1, 3,2
314 DATA 219,255,255,255,127,16,32,6
    4
315 DATA 219,255,255,255,255,24,60,6
    0
316 DATA 219,255,255,255,254,8,4,2
317 DATA 248,248,240,224,128,128,192
    ,64
318 DATA 6,5,6,12,127,0,0,0
319 DATA 128,0,0,0,0,0,0,0
320 DATA 60,126,126,126,60,60,60,60
321 DATA 1,0,0,0,0,0,0,0
322 DATA 96,160,96,48,254,0,0,0
323 DATA 24,24,24,24,24,0,0,0
324 DATA 128,192,240,240,248,252,254
    ,255
325 DATA 129,195,231,255,255,255,255
    ,255
326 DATA 128,192,192,224,224,224,248
    ,255
327 DATA 1,3,7,31,63,63,127,255
328 DATA 1,3,7,7,15,31,63,255
329 DATA 255,255,255,255,255,254,249
    ,7
330 DATA 252,251,247,207,191,127,255
    ,255
331 DATA 255,255,255,255,255,255,255
    ,255
400 REM PUT PLAYFIELD ON SCREEN
420 GRAPHICS 2:POKE 752,1
500 REM TELL COMPUTER WHERE TO FIND
    NEW CHARACTER SET
510 POKE 756,CHBASE/256
530 SETCOLOR 0,3,6:SETCOLOR 1,8,6:SE
    TCOLOR 2,1,10:SETCOLOR 3,0,10
540 REM PLOT CHARACTERS USING COLOR
    DATA
550 FOR ROW=0 TO 9
560 FOR COLUMN=0 TO 19
570 READ CHAR
580 COLOR CHAR
590 PLOT COLUMN,ROW
600 NEXT COLUMN
610 NEXT ROW
620 REM PRINT STANDARD NUMBERS AND L
    ETTERS IN TEXT WINDOW
630 ? :? "FUEL:2568 STARDATE:174 A
    LTITUDE:390";
640 REM BLINK ENGINE EXHAUST
650 FOR LUM=0 TO 8 STEP 2
660 SETCOLOR 0,3,LUM
670 NEXT LUM
680 GOTO 650
699 REM CHARACTER COLOR DATA
700 DATA 0,129,0,0,0,0,131,0,132,0,1
    33,0,0,132,0,0,0,0,0,131
701 DATA 0,0,0,133,0,0,0,0,6,7,8,0,1
    29,0,0,129,0,133,0,0
702 DATA 0,133,0,0,132,0,9,10,11,11,
    11,12,13,129,0,0,131,0,129,0
703 DATA 0,0,132,0,0,0,14,15,27,27,2
    7,28,29,0,133,0,0,0,0,132
704 DATA 202,133,0,132,0,133,30,31,6
    4,64,64,98,103,0,129,0,206,202,1
    32,0
705 DATA 215,203,202,0,0,0,129,133,7
    2,72,72,0,133,0,206,203,215,215,
    205,0
706 DATA 215,215,215,205,133,0,206,2
    03,215,202,133,0,0,208,215,215,2
    15,215,215,202
707 DATA 215,215,209,214,215,215,215
    ,215,215,215,215,209,214,215,215
    ,215,215,215,215,215
708 DATA 215,215,215,215,215,215,215
    ,215,215,215,215,215,215,215,215
    ,215,215,215,215,215
709 DATA 215,215,215,215,215,115,99,
    111,114,101,26,21,16,19,23,215,2
    15,215,215,215

Character Editor
This simple utility program allows you to design your own
Atari custom characters.

playfield example
An example of the playfields you can create with custom
characters. This screen was generated by one of the following
sample programs.