TRS-80 graphics made almost painless. (part 1) John Crew.
TRS-80 Graphics Made Almost Painless
Part 1
This is the first of a three-part series on graphics creation for purposes such as doodling, making limited resolution artwork, and designing graphics for your own programs.
The programs are intended to simplify graphics creation for the above purposes, and should be of interest to novice and expert computer users.
This article describes an etch-a-sketch program that I call Sketch/Print. The second article describes a program, called Vector Plotter, which draws lines between any two points on the screen that you specify. The last article describes a program, Graphics Manager, which stores whatever is on the screen. Graphics Manager can store up to nine pictures, which I call frames, that can have either standard or double width characters. Using Graphics Manager, frames can be saved on tape, loaded from tape, compressed, printed on paper, combined, and have the ASCII number of every byte in them listed.
Sketch/Print and Vector Plotter can be used independently, or you can add Graphics Manager to either. I recommend that you type them as shown alone, test them individually, and correct your typographical errors, and then if you desire, follow the instructions in Part 3 of this series to add Graphics Manager to one or both of the others.
Programmers who have more than 16K of free RAM may want to combine all three programs. That is a fairly simple task if you know Basic well, have about 18K of free RAM, and have an excellent line renumbering program.
System Requirements
All of the programs in this series are written in Level II Basic for an unmodified Model I, 16K, cassette system. All programs except Graphics Manager will easily fit into 4K of free RAM. Using Graphics Manager with one of the other programs requires at least 16K of free RAM, and it is a tight fit so there probably is not enough room for anything else except a very short program such as a simple key debounce program.
To print frames on paper using Graphics Manager you need an MX-80 printer (the basic model without the new features is adequate), or you will have to modify the program. The article on Graphics Manager will describe how frames are stored, which should be very helpful to those who want to modify the program.
Because I used POKE statements and some other tricks which are unique to the previously described system, the programs in this series will probably require modifications to work on a Model III, a differently configured Model I, or other computer.
I spent many hours developing and debugging the programs in this series so I do not think they contain any errors. The programs have many tests to reject clearly erroneous commands. The only program I am aware of is that some parts of the programs are not written in the most efficient and neat manner. There are no syntax errors, so do not change any statements which look wrong to you. If you find statements which you think are unnecessary, please leave them alone; there is probably a good reason for their inclusion.
One good book which helped me gain the skills and knowledge which I needed to write these programs was William Barden's Programming Techniques for Level II Basic which is sold by Radio Shack. I highly recommend that book to intermediate Basic programmers who want to become more versatile.
Program Modification
The three main programs are written very compactly to save memory space and execution time. To this end I willingly sacrificed some legibility and ease of comprehension. For Basic programs they are rather fast. They could be made even faster if you rewrote them so the subroutines were put as close to the beginning as possible with the most frequently used subroutines first.
Another way to make the programs run faster if you have memory in the expansion interface is to set the mrmory size to 32769 so Basic will use the faster RAM in the keyboard. When you type them, omit all REM statements.
I strongly urge you to learn about the EDIT mode of Level II Basic before typing any program which has long lines since that knowledge will probably save you much frustration. Where you see what appears to be a long string of blanks, in the program I have used the key to start a new line on the screen; there are no long strings of blanks in my programs because they waste space and formatted output is better produced with STRING$ or TAB in a PRINT statement, or, of course, PRINT USING.
I used many tricks to save memory, some of which I have rarely or never seen used before. For example, there are only two cases in which a semicolon is needed in a PRINT statement: at the end ofa PRINT statement to suppress a line advance, and to indicate the separation of two variable names. Many people of two variable names. Many PRINT statements.
Figure 1 gives examples of compact PRINT statements which are designed to print the current values of two variables named A and B. Notice in particular that the first example will not work as intended; it will print a single value which is the value of a variable named AB if such a variable is used in the hypothetical main program. If AB is not used elsewhere, Level II will set aside space for AB and set its value to zero. Also notice that putting a space between the A and the B will not affect that PRING statement, because Level II Basic almost always ignores spaces in statements. The other examples will properly print two values.
About Sketch Print
Most of the etch-a-sketch programs which I have seen range in quality from mediocre to dreadful. I decided to write a better program which would use a small graphics block instead of a large graphics character, which was compact and efficient, and which did not behave oddly when the edge of the screen was reached.
Sketch/Print can work in two different ways (modes): graphics mode and alphanumeric mode. When you run it, you will first see the instructions. Next you will see a small graphics block at the lower lefthand corner of the screen. When that block appears, you are in the graphics mode.
The Graphics Mode
In the graphics mode you can move the cursor using the keys 1-9 on the numeric keypad (or the numeric keys on the main keyboard) in a pseudo-joystick fashion. The 8 key moves the cursor straight up, the 9 moves it diagonally upward to the right, the 6 moves it to the right, etc.
Using the 5 key, you can turn on a graphics block at the current cursor location. The other keys (1-3, 4, 6, 7-9) first move the cursor and then turn on a graphics block. The keys in the numeric keypad will repeat as long as you hold them down. If you find the rate of repetition too fast, increase the value assigned in line 380 to the variable named T and insert this at the beginning of line 350:
T=#:GOSUB410:
(using a digit in place of #).
Each time you press a key which moves the cursor, the direction is checked to be sure that it will not move the cursor off theedge of thescreen. If the direction is illegal, then the cursor movement command is ignored.
Holding the SHIFT key down while a numeric key is depressed will erase instead of turn on a block.
To move the cursor to a different position without erasing or drawing over existing graphics, press the decimal point key. This will switch to a flashing cursor which will not disturb your graphics characters, but you will have to be careful not to move through or under an alphanumeric character (which will be mentioned later in detail). To return to the normal cursor for the graphics mode, press the decimal point and the SHIFT keys simultaneously.
You can also draw and erase lines automatically while in graphics mode. Press the S key to store the current cursor location for later reference when automatically drawing lines. To draw a line from the last stored location to the present location, press the D key.
To erase a line from the last stored location to the present cursor location, press the E key. The stored location is initially set to the coordinates of the lower lefthand corner of the screen.
Switching Modes
To switch to the alphanumeric mode, press the SHIFT key and the key. To return to graphics mode, press the SHIFT key and the .
The Alphanumeric Mode
In the alphanumeric mode you may type on the screen any displayable character which is accessible from the keyboard except the lower case letters. Listing 1 displays the characters which may be used. Any lower case letter which you use will be converted to upper case. The left arrow key may be used to backspace and erase the last character. You cannot go beyond the top or bottom of the screen.
Restrictions
There are two restrictions imposed on the program by the design of the Model I.
The first restriction is that, as noted above, lower case letters can't be used in the alphanumeric mode. This is because the unmodified Model I has only seven instead of eight bits for each location in the video memory (bit 6 is not stored). You will see a character with an ASCII number 641 less than the one you POKEd if you POKE a character with an ASCII code of 96-127 or 192-255. If you POKE an ASCII value less than 32, you will see a character with an ASCII number 64 greater than the POKEd code.
Line 192 contains the POKE statement which puts an alphanumeric character into video memory and also converts lower case letters to upper case. If you have a working lower case modification, you may want to modify this program to allow lower case letters. I believe that the only change needed is to use the EDIT mode of Level II to delete +32{N>95) from the second POKE statement in line 192.
The second restriction is that you can't move through or immediately under an alphanumeric character while you are in the graphics mode of Sketch/ Print. This is because the Model I has character graphics instead of a separate display mode for graphics such as the Color Computer has.
On the Color Computer you could write a program to draw alphanumeric characters while in one of the high resolution graphics modes, so you could freely draw over the alphanumeric characters. But, alas, on the Model I you are restricted to the characters listed in the C appendix of the Level II reference manual.
The only way to make two characters on the screen appear to overlap is to flash them alternately at high speed, a trick which this program cannot accomplish.
There are 1024 character positions on the Model I screen. Each position can hold either an alphanumeric character or a graphics character. Alphanumeric characters have a blank space below them while graphics characters may fill a character position. The blank space under an alphanumeric character is part of that character.
If you try to SET a point in a position which is occupied by an alphanumeric character, that alphanumeric character will be replaced by a graphics character. Because each alphanumeric character has a blank space below it which is associated with that character, you can't set a point in the blank space below the alphanumeric character.
Program Notes
I wanted the keys which move the cursor in the graphics mode to repeat. This can be accomplished in two ways: by writing a keyboard scan subroutine wither in Basic using PEEK statements or in machine language, or by erasing the keyboard buffer used by Level II and using the INKEYS$ function to scan the keyboard. I used the second method.
Level II maintains a buffer which contains a record of the last keys pressed. It occupies positions 16438-16444 in memory. This buffer is referred to after the keyboard has been scanned so the computer can determine which new key has been pressed. This provides keyboard rollover without elaborate hardware.
If zeroes are POKEd into the keyboard buffer, the computer does not know which keys were previously pressed and recognized. For a more complete description of how the keyboard is used by Level II see the book by William Barden which I mentioned earlier.
You may wonder why I used POKE instead of PRINT @ to put a character on the screen. I used POKE because even if you put a semicolon at the end of a PRINT @ statement the screen will scroll when you put a character at position 1023 (the lower irghtand corner of the screen).
The multiple IF-THEN-ELSE statements in Sketch/Print are used to avoid using many GOTO statements to jump past the long list of tests. Using lines which have multiple IF-THEN-ELSE statements saves memory and makes the program run fast. Also, a program written that way will appeal more to programmers who like structured programs.
When you write multiple IF-THEN-ELSE statements on one program line, remember to put the highest priority IF-THEN tests first, and, if the logic is complex, make a flowchart.
One of the biggest problems I encountered in writing Sketch/Print was finding an efficient way of testing which directions of motion in the graphics mode were illegal. There are eight different illegal cases. Four of them occur when the cursor is in a corner of the screen. The other four occur when the cursor is at one edge of the screen but not in a corner.
At first I thought eight IF-THEN statements would be needed, but later I thought of a clever method that required only three IF-THEN-ELSE statements. An array with nine elements named ID is used to hold flags which indicate which directions are illegal. Each position in the ID array corresponds to a key in the numeric keypad. The fifth position in the array corresponds to the 5 key which does not move the cursor so it is never an illegal direction.
The IF-THEN-ELSE statement in line 210 checks to see if the cursor is at the left or right edge of the screen and if one of those situations exists, sets appropriate flags indicating which horizontal directions are illegal.
The IF-THEN-ELSE statement in line 220 checks to see if the cursor is at the top or bottom of the screen, and, if one of those situations exists, sets appropriate flags indicating illegal vertical directions.
In line 250, the direction of motion you request is compared with the list of illegal directions. If the direction is illegal, the computer goes back (to line 170) and wawaits your next command. When the cursor is in a corner one illegal direction flag is set by both the test for illegal horizontal directions and the test for illegal vertical directions. That is a minor inefficiency.
If you plan to modify Sketch/Print or want to learn how it works, look at Figure 2 which lists the variables used in the program.
You might want to modify Sketch/ Print so it would do one, several, or all of the following functions on command: reverse graphics; draw a border; scroll the screen left, right, up, or down; or automatically draw a triangle, rectangle, ellipse, circle, or other figure.
Table: Figure 1. Examples of Compact PRINT Statements.
Table: Listing 1. Characters Allowed in Alphanumeric Mode of SKETCH/PRINT.
Table: Listing 2. Example of SETting a Point in a Location Occupied by an Alphanumeric Character.
Table: Listing 3. SKETCH/PRINT
Table: Figure 2. Variables Used By Sketch/Print
Photo: Sample RUN of SKETCH/PRINT.
Photo: Two Sample Pictures Made with SKETCH/PRINT.