5

Screenbyter

titlebar.gif

Carl Zahrt and Orson Scott Card


Here is an artist's utility that lets you create screen displays in any of the regular pixel graphics modes--and GRAPHICS "6.5" (XL Mode 14) and "7.5" (XL Mode 15) as well. It's simple enough for a child to use. It gives you complete control over color, mode, and display size. And a special Fill Mode lets you draw long lines or fill large areas with color in moments. "Screenbyter" requires 40K memory and a disk drive.

For color graphics, the Atari home computers are superb. Creating screen displays from BASIC, page flipping, scrolling, redefining characters, continuous memory, and changing from mode to mode to get exactly the effect you want--once you've worked with graphics on the Atari, most other home computers feel a bit confining.

But that doesn't mean using Atari graphics is easy, especially if you want large displays which extend far beyond the edges of the TV screen, or detailed drawings that would take hundreds of PLOT and DRAWTO statements to create from BASIC. Such things take painstaking work on graph paper and many POKEs into screen memory--or a good chunk of your paycheck for software to do it for you.

"Screenbyter" takes the pain out of creating beautiful graphics displays.


Using Screenbyter

Setup. Screenbyter begins by displaying a directory of all files on the disk with the extender ".PIX." This extender is automatically added to all files created by Screenbyter. If no directory appears, there are no previously saved files on the disk.

"What file should hold your finished screen? (Eight characters)." Respond to this prompt by giving the filename you want your new display to have, when you save it at the end of the editing session. Screenbyter automatically removes everything before a colon or after a period and replaces the characters with "D1:" and ".PIX', so that you need to enter only the eight-letter filename. If you use illegal characters, Screenbyter will ask you to try again; if you use more than eight characters, only the first eight characters will be used.

If the name you enter is the name of a file already on disk, Screenbyter will remind you of that. To change the name, press RETURN. Or, if you want your new display to overwrite the old file, press any other key to go on.

"Would you like to edit a screen you have already saved? (Y or N)". If you answer Y, Screenbyter asks you for the name of the saved file. If the file is not on disk in the form "D1:filename.PIX", Screenbyter will tell you and ask you to insert the correct disk or, if you wish, ask you again if you want to edit a previously saved screen.

Once the file is found, Screenbyter reads the first four bytes of the file to get the mode number, the number of bytes per line, and the number of lines in the display as it was saved. Press RETURN if you want to change these parameters. Press any other key to leave them the same.

Changing the parameters can have interesting effects. Remember that four-color modes all read the bytes the same way; if you want to draw your displays in GRAPHICS 3 (ANTIC 8) and then display them in a higher four-color mode, you can.

Changing the length of a file either chops off the bottom or adds blank lines at the bottom of the display. Changing the line width, however, will usually result in garbage, since the vertical relationships will all be changed. The option is included, however, because sometimes garbage can be fun, and who are we to forbid you to change the line width just because we can't think of a reason for doing it?

If you are not editing a previously saved display, or if you are changing the parameters, you get the following series of prompts:

"What Antic mode will you work in?" This prompt is followed by a table, which lists the eight ANTIC pixel modes and their graphics mode equivalent. ANTIC 8, for instance, is GRAPHICS 3; ANTIC F (15) is GRAPHICS 8. Two ANTIC modes, C (12) and E (14), have no graphics equivalent--they are the famous "GRAPHICS 6.5" and "GRAPHICS 7.5." (See Table 1.) Enter the ANTIC mode number: 8, 9, A (10), B (11), C (12), D (13), E (14), or F (15).

"How wide a line? (Minimum nnbyte, maximum nnbytes)." Depending on the mode you choose, Screenbyter will give you minimum and maximum number of bytes per line. Remember that in the four-color modes, each byte is four pixels, while in the two-color modes, each byte is eight pixels. The minimum is based on the minimum number of bytes required to fill the screen. The maximum is based on the widest possible line that will allow the display to fit within 4K. If you enter numbers outside the legal range, Screenbyter will select the minimum or maximum, as appropriate.

With ANTIC E and F, the minimum and maximum are the same--you have no option, so any number you enter will result in the same number of bytes per line. This is because these two modes will not scroll--they both require more than 4K. Scrolling a screen that crosses a 4K boundary requires elaborate arrangements of screen memory that were beyond the scope of this program. Displays created in E and F will take up 65 sectors on disk; all other displays will take up 33 sectors or fewer.

"How many lines do you want to edit? (Minimum nn,maximum nn)" The minimum and maximum depend on the mode and the number of bytes per line already selected. Again, if you choose parameters outside the legal range, Screenbyter will select the minimum or maximum. And if you choose the maximum number of bytes per line, only the minimum number of lines per screen will be possible.

When all selections have been made, you are given one last chance to change your mind. All the parameters you chose are displayed on the screen. If these are correct, press START, and the program will go on. If you want to make changes, press OPTION and the program will start over.

Waiting. What's going on while you wait? Screenbyter configures the memory to reserve 10K (40 pages) at the top of memory to hold screen memory (up to 8K), the display list, and the machine language routine that actually puts your drawing on the screen. Screen memory is cleared and the machine language routines are loaded. If you chose to edit a previously saved screen, it is loaded into memory now. All this takes about six seconds. The rest of the time is spent writing the display list. The higher the ANTIC mode, the longer it takes to write the display list--ANTIC F requires about 200 POKEs in BASIC, plus the calculations to find out what numbers to POKE, and it can take as long as 20 seconds.

When Screenbyter is ready for you to edit, there will be a cursor in the upper-left-hand corner.

Moving the cursor. The joystick controls the cursor.

Drawing a line. Hold down the joystick button to draw; let it up to move the cursor without drawing.

Selecting a color. Press 1 or SHIFT-CAPS/LOWR to select Color 1. Press 2 or CONTROL-CAPS/LOWR for Color 2. Press 3 or SHIFT-CONTROL-CAPS/LOWR for Color 3. Press 0 or CAPS/ LOWR to select the background color. Drawing in the background color has the effect of erasing.

Color Mode. To change the actual colors that are displayed by Colors 1, 2, or 3, or the background color, press START. You will hear a buzz, and the cursor will no longer respond to the joystick. Instead, moving the joystick will change the colors displayed on the screen. Moving the joystick up or right will change the color from darker to brighter, then jump to the darkest value of the next color. Moving the joystick down or left will change the color from brighter to darker, then jump to the brightest value of the next color.

To change the background color, move the joystick forward or back; to change Color 3, move the joystick left or right. To change Color 2, move the joystick forward or back with the button pressed; to change Color 1, move the joystick left or right with the button pressed.

To return to Cursor Mode, press START again. No other commands will work during Color Mode.

Slow Mode. Press the space bar to enter Slow Mode. A delay loop in the program makes the cursor move much more slowly around the screen, with a click between moves. This mode allows you to create details. To return to Fast Mode, press the space bar again.

Fill Mode. Press the inverse key (Atari logo key) to enter Fill Mode. A low hum will come from the television. In this mode, when you press the joystick button, Screenbyter draws a dot of the selected color at the current cursor location, as usual, but it also searches to the right along the same line. If it finds another dot of the same color before it reaches the end of the line, it will fill in all the area between that dot and the current cursor position with dots of the same color. If no dot of the same color is found, no fill operation is performed.

This allows you to fill large or small areas of the screen with a single color. Simply draw the right-hand edge of the figure first; then enter Fill Mode and draw the left-hand border. It takes some practice to use this function without accidentally erasing parts of your screen, but you will probably find that this is the most useful feature of Screenbyter.

To exit Fill Mode, press the inverse key again. The hum will continue as long as you are in Fill Mode, and will stop only when you leave.

Insert a line. Press SHIFT-INSERT to insert a line at the current cursor position. The bottom line of the display will be pushed down and lost.

Delete a line. Press SHIFT-DELETE to delete the current cursor line. A blank line will be added at the bottom of the display.

Clear the screen. Press CONTROL-SHIFT-CLEAR to completely erase the screen. If you haven't already saved the display, it will be lost.

Saving the screen. Press SELECT to save the screen without ending the editing session. The current screen display will be saved as "D1:TEMPFILE.PIX". You can save as often as you like; Screenbyter will simply overwrite any existing TEMPFILE.PIX file.

Ending the editing session. Press OPTION to save the screen and end the editing session. (To exit without saving, press RESET.) The display will be saved as "D1:TEMPFILE.SCR." Then the regular GRAPHICS 0 screen will return, and you will be given several prompts:

"Do you want to save the screen as D1:filename.PIX? (Y or N)". If you answer N, the saved display will be left as TEMPFILE.PIX. If you answer Y, Screenbyter will erase any existing file that has the same filename. Then Screenbyter will rename TEMPFILE.PIX with the filename you chose.

"Do you want to quit? (Y or N)". If you answer Y, Screenbyter will restore the old top of memory and exit to BASIC. If you answer N, you will get another prompt. To return to edit the screen you just left, press OPTION. That display will be reloaded into memory, the display list will be rewritten, and you can start over. To edit an entirely new screen, or to change the name of the save file, press START. In effect, Screenbyter will then start over.


What's Going On inside Screenbyter?

Like everything else in a computer, your display exists as a series of numbers stored in binary form in memory locations in the computer. The ANTIC chip scans screen memory as it is instructed to do by the display list. But it doesn't read the numbers as numbers. Instead, it reads them as patterns of "on" and "off" bits.

Four-color modes. In the four-color modes, each byte is read as code for four pixels. The eight-bit binary number is treated as four bit-pairs:

00 00 00 00

Each bit-pair provides the code for one pixel, or rectangle of color on the screen. In GRAPHICS 3, each pixel is the size of a character in GRAPHICS 0. In GRAPHICS 7.5, each pixel is one scan line high and two color clocks wide, which gives very good resolution. But all four-color modes read the bit-pairs the same way.

00 means to display the background color (the color code stored at location 712).

01 means to display Color 1 (the color code stored at location 708).

10 means to display Color 2 (the color code stored at location 709).

11 means to display Color 3 (the color code stored at location 710).

This means that the number 216 (binary 11011000) is treated as four pixel-color instructions: The first pixel is Color 3, the second pixel is Color 1, the third pixel is Color 2, and the last pixel is the background color.

Two-color modes. The two-color modes treat each bit as a separate pixel instruction, so that each byte controls eight pixels. An "on" bit, or 1, is read as a Color 1 instruction, while an "off" bit, or 0, is read as a background color instruction. In a two-color mode, the number 216 would be treated as eight pixel-color instructions: Two "on" pixels, one "off" pixel, two more "on" pixels, and three "off" pixels. (See Table 1 for a listing of all the modes.)


Table 1. Pixel Modes

ANTIC mode 8 9 A(10) B(11) C(12) D(13) E(14) F(15)
Graphics mode 3 4 5 6 -- 7 -- 8
Colors 4 2 5 2 2 4 4 2
Resolution 24x40 48x80 48x80 96x160 192x160 96x160 192x160 192x320
Memory, bytes 240 480 960 1920 3840 3840 7680 7680
(sectors) (3) (5) (9) (17) (33) (33) (65) (65)
                 
Lines/screen 24 48 48 96 192 96 192

192

Bytes/line 10 10 20 20 20 40 40 40
Bits/pixel 2 1 2 1 1 2 2 1
(pixels/byte) (4) (8) (4) (8) (8) (4) (8) (4)
Scan lines/pixel 8 4 4 2 1 2 1 1
Color clocks/pixel 4 2 2 1 1 1 1 1/2

Note: ANTIC C (12) and E (14), the two "hidden" pixel modes, provide the same resolution. All the other pixel modes attempt to create as square a pixel as the TV screen allows--the same number of color clocks wide as scan lines high. C and E, however, are twice as wide as they are high, making each pixel very short and wide. They come very near the resolution of ANTIC F (GRAPHICS 8). The advantages are that, compared to F, C uses half the memory and E allows four colors.


Moving around the screen. Moving the cursor around the screen, then, isn't simply a matter of moving from one byte to the next in screen memory. Screenbyter also has to move from bit to bit or from bit-pair to bit-pair within the bytes. This can be done in BASIC by adding or subtracting values, but it is very slow. Machine language, however, has powerful commands that make it easy to move from bit to bit. DRAWTO and PLOT commands do these manipulations for you, but since Screenbyter is circumventing the BASIC graphics commands entirely, the main drawing operations are executed in machine language.

To understand what Screenbyter is doing, you need to understand a few machine language commands: EOR, ORA, and AND. The two OR instructions and the AND instruction are not the same as the AND and OR you use in Atari BASIC. In machine language, these are operations on the bits of an eight-bit number, and are often called "bitwise" AND and OR to help keep the difference in mind.

All three operations compare two numbers, one stored in the accumulator and another somewhere else in memory. The operation results in a third number, which is stored in the accumulator in place of the number that was already there.

AND, referred to as "bitwise AND," compares the two numbers, bit by bit. Any bit that is on in both numbers stayson in the resulting number. All other bits are turned off. In other words, only bits that are on in the first number andin the second number remain on in the result.

               10010110 
         AND   11110000
  results in   10010000

ORA, referred to as "bitwise OR," compares the two numbers, but in this case any bit that is on in either number stays on in the result:

               10010110 
          ORA  11110000
   results in  11110110

EOR, referred to as "exclusive OR," compares the two numbers, and any bit that is on in one and only one number is left on in the result. Any bit that is on in both numbers or off in both numbers is off in the result:

               10010110 
          EOR  11110000
   results in  01100110

How do these actually work, in practice?

Screenbyter maintains several masks.The Color Mask is in page six, at memory location 1692 ($069C). This byte is set from BASIC whenever the color is changed, and it is set so that every bit or bit-pair represents a pixel of the selected color. If the background color is selected, the Color Mask is 00000000. If Color 1 is selected, the Color Mask is 01010101. For Color 2, the Color Mask is 10101010, and for Color 3 it is 11111111. With two-color modes, the Color Mask is either 00000000 or 11111111.

The Cursor Mask is kept at location 1696 ($06A0). It is set to represent the current cursor pixel within the cursor byte. The bits in the current pixel are on; all others are off. In four-color modes, if the cursor is in the leftmost pixel of the cursor byte, the Cursor Mask will be set to 11000000; if it is in the rightmost pixel, the mask will be set to 00000011. The two middle pixels are 00110000 and 00001100. In two-color modes, a single "on" bit represents the cursor position.

Whenever you move the cursor left or right or diagonally, the Cursor Mask is shifted left or right, so that at any given moment the Cursor Mask will mark which bit or bit-pair Screenbyter should change.

If you are drawing, Screenbyter first picks up the value of the current cursor byte and stores it at 1690 ($069A). Then it picks up the Cursor Mask and EORs it with 11111111 (decimal 255). This reverses the Cursor Mask--any bit that was on is now off, and any bit that was off is now on.

Let's see that in action in a four-color mode, in which the background is black, Color 1 is red, Color 2 is green, and Color 3 is blue. The bit-pairs will be separated in these examples, to make it easier to keep track of the pixels.

    Cursor Mask   00 11 00 00
            EOR   11 11 11 11
     results in   11 00 11 11  (Reverse Cursor Mask)

Screenbyter then ANDs the Reverse Cursor Mask with the number at 1690 ($069A), which in effect makes a hole in the cursor position:

Reverse Cursor Mask   11 00 11 11
                AND   01 01 01 11   red   red   red   blue
         results in   01 00 01 11   red   --    red   blue

The two bits in the cursor position will always be turned off.

Now Screenbyter must prepare the pixel code to go in that hole. Screenbyter picks up the Cursor Mask and ANDs it with the Color Mask. Since all the bits in the Cursor Mask are off except the two bits of the current pixel, the resulting number will have only the bits that represent the current color, and only in the pixel position:

      Cursor Mask   00 11 00 00
   AND Color Mask   10 10 10 10     green green green green 
       results in   00 10 00 00      --   green   --    --  

Now we are ready to put the correct pixel code into the hole in the current cursor byte. To do this, we bitwise OR the current pixel (the one with the cursor byte with a hole in it) we just got from the operation before. Remember that with ORA, any byte that is on in either or both of the two numbers is on in the result:

               correct pixel     00 10 00 00    --   green   --     --
  ORA current byte with hole     01 00 01 11    red    --    red   blue	 
                  results in     01 10 01 11    red  green   red   blue

The result is then stored in 1690 ($069A), and later in the program it is put into screen memory.

If you are not drawing, but just moving the cursor, the operation is a little different, but AND, EOR, and ORA perform the same functions.

Machine language is so fast that all this seems to happen instantaneously. In fact, the only reason the cursor doesn't fly around the screen out of control is because Screenbyter keeps leaving the machine language routine, returning to BASIC to check the keyboard for other commands. Even so, the cursor moves so quickly that it has to be slowed down in order to allow you to draw details.

Use of page six. The machine language routine at SCROLL uses a field in page six to hold some important variables. The memory locations in page six are explained in Table 2.


Screenbyter Displays in Your Own Programs

Here are two routines you can add to your own programs, which will allow you to load the displays you created with Screenbyter. The first routine, Load and Display List, works with any Screenbyter file. However, it sets up a custom display list with individual LMS instructions, suitable for scrolling. This makes the set-up time rather long. So a Simple Load Routine is also included. It will work with any display file that was created using the minimumline width and number of lines per screen, except screens created in ANTIC C and E (GRAPHICS "6.5" and "7.5"). You cannot use it if you intend to scroll horizontally. However, you canuse it if you intend to scroll vertically or flip pages, and your display was created with the minimum line width.

Both routines will configure memory to protect the screen display, read the display parameters from whatever display file you choose, and load the file into memory. It uses a load routine very similar to the one used by Fontbyter, so we won't explain them again here.


Table 2. Page 6 Memory locations

Dec
1670

1671

1672
1673

1674-1675
1676-1677
1678

1679
1680

1681
1682

1683
1684

1685
1686-1687

1688-1689

1690
1691

1692
1693
1694
1695
1696
1697
1698


1699

1700


1701

1702-1704


Hex
0686

0687

0688
0689

068A-068B
068C-068D
068E

068F
0690

0691
0692

0693
0694

0695
0696-0697

0698-0699

069A
069B

069C
069D
069E
069F
06A0
06A1
06A2


06A3

06A4


06A5

06A6-06A8



WIDE - 1. Used to check for the end of the logical
line.
Used in fill routine to keep track of right border
of fill.
Cursor location: current byte on logical line.
Used by the fill routine to hold the pattern of the
rightmost byte of the fill line.
LINE - 1. Used to check for last line of display.
Cursor location: current logical line number.
Bytes per screen line--1. Used by the scrolling
routine to check for the end of the screen line.
Cursor location: current byte on screen line.
Lines per screen--1. Used by the scrolling routine to
check for the bottom of the screen display.
Cursor location: current screen line number.
Used by the fill routine to hold the pattern of the
leftmost byte of the fill line.
A temporary holding location.
Used by the fill routine to hold the real value of
the byte currently being tested.
A temporary holding location.
The current screen starting address (the address
of the upper-left-hand corner of the screen).
Cursor location: the address of the current cursor
byte in screen memory.
The real contents of the current cursor byte.
The reverse (cursor display) contents of the
current cursor byte.
Color Mask.
The number of bits per pixel (1 or 2).
Scroll flag (0 = do not scroll).
Fill flag (0 = do not fill).
Cursor Mask.
Joystick value.
Total number of lines per screen. Used in the
scroll routine to change the correct number of
LMS instructions in the display list.
WIDE. Used in the scroll routine to increment
the LMS addresses in the display list.
Fill Test Mask. Used in the fill routine to isolate
and test each pixel until a pixel of the selected
color is found.
Starting Fill Test Mask. Either 192 (four-color
mode) or 128 (two-color mode).
Machine language jump vector: JMP followed by
the address of the fill subroutine held in the
string FILL$.

Notice that in loading displays created in ANTIC E (14) and F (15) (GRAPHICS 7.5 and 8), the screen display must cross a 4K boundary line. The ANTIC chip gets fussy at this point, and ignores anything after a 4K boundary line until the beginning of the line pointed to by the next LMS instruction. Therefore, screen memory must be arranged so that the 4K boundary line comes right at the end of a line; the display list routine will have set the value of SC, the start of screen memory, so that the 4K boundary line will fall right at the end of a line.

If you have an XL model (600XL, 800XL, 1200XL, 1400XL, or 1450XLD), ANTIC C and E can be accessed from BASIC using the statements GRAPHICS 14 and GRAPHICS 15, respectively.


Program 1. Load and Display List Routine

Download P168L1.BAS (Saved BASIC)
Download / View P168L1.LST (Listed BASIC)

Program 2. Simple Load Routine

Download P169L2.BAS (Saved BASIC)
Download / View P169L2.LST (Listed BASIC)

Screenbyter

After the main listing of the BASIC program, you will find several programs to create disk files containing the machine language routines used in Screenbyter. If you prefer, you can easily add these DATA statements to your program and read them that way, or--as I prefer to do--load them into string constants and use them that way, without so many disk accesses. However, typing in strings that have lots of inverse and control characters in them can be tedious and often leads to typing errors, so these DATA statements are necessary in the published version of the program.

If you are also using Fontbyter, you might notice that Screen byter follows the same structure. That's because Fontbyter was used as the starting point, and changed wherever Screenbyter's needs were different. However, the line insert, line delete, and clear screen machine language routines are not identical, so don't try to use the similar Fontbyter routines for Screenbyter--you will hopelessly confuse your Atari if you do, and confused Ataris have a way of locking up or otherwise expressing their frustration.

(And an acknowledgment: Our thanks to Steve and Tammy Rector at the Computer Shop in South Bend, Indiana, for their help in keeping this project from getting lost between Taiwan and Greensboro.)


Program 3. Screenbyter

Download P170L3.BAS (Saved BASIC)
Download / View P170L3.LST (Listed BASIC)

Program 4. Insert Line Routine

Download P177L4.BAS (Saved BASIC)
Download / View P177L4.LST (Listed BASIC)

Program 5. Delete Line Routine

Download P178L5.BAS (Saved BASIC)
Download / View P178L5.LST (Listed BASIC)

Program 6. Cursor Movement Routine

Download P178L6.BAS (Saved BASIC)
Download / View P178L6.LST (Listed BASIC)

Program 7. Clear Screen Routine

Download P181L7.BAS (Saved BASIC)
Download / View P181L7.LST (Listed BASIC)

Program 8. Fill Subroutine

Download P181L8.BAS (Saved BASIC)
Download / View P181L8.LST (Listed BASIC)

Return to Table of Contents | Previous Section | Next Section