Printing Characters In Mixed Atari Graphics Modes
2 Swan Terrace
Greenwich, CT 06830
For those of you who have been anxiously awaiting this appendum, I apologize. Time conflicts and the discovery of redefinable character sets have prohibited me (until now, of course) from writing it. For those of you who haven't, get hold of the Sept/Oct 1980 issue of COMPUTE! and read up on "Designing Your Own Atari Graphics Modes." This article won't be of much use to you until you do.
The problem, if you recall, is with printing characters on mode lines that are out of the usual range of that mode. For example, if we design a graphics mode such that the thirtieth line is mode two, we would get an error message if we attempted to print on that line. This is because the Atari thinks it is in the regular mode two, which only allows twelve lines of characters. We must therefore find another way to put the characters on the screen.
As you may already realize, the screen is just a type of window looking into a part of memory. If you change that memory, what you see on the screen also changes. The solution, therefore, is just to POKE the characters into the memory locations that correspond to the positions on the screen where we want them to appear.
Where Is the screen In memory?
We already know where the display list is in memory; we used the variable BEGIN to point to it last time:
BEGIN = PEEK(560) + PEEK(561)*256 + 4
But, you may well ask, what does this have to do with the screen memory, or display memory as we will call it here? It just so happens that the first two memory locations in the display list point to the beginning of display memory in the following fashion:
DISMEN = PEEK(BEGIN) + PEEK(BEGIN + 1)*256
If you recall, we never used the first two memory locations in the display list last time; now you know why.
How do we calculate the exact memory locations to POKE Into?
Each mode line used up a certain amount of memory. As you might guess, different modes use different amounts of memory per line. To be more exact:
So all we have to do is figure out how much memory is used before the mode line that we want to print on, and add that to DISMEM to determine where we want to start POKEing. As an example of how to do this, let's suppose we have a gaphics mode with four lines of mode 1, fifty lines of mode seven, three lines of mode four, and three lines of mode two (4×8 + 50×2 + 3×4 + 3×16 = 32 + 100 + 12 + 48 = 192); and we want to print on the second line of mode two. Checking the table above, we go:
|4 lines of mode 1 = 4×20 =||80|
|50 lines of mode 7 = 50×40 =||2000|
|3 lines of mode 4 = 3×10 =||30|
|1 line of mode 2 = 1×20=||20||(remember, we only|
|count the lines above|
|the one we want to|
|For a grand total of:||2130|
Therefore, memory location DISMEM + 2130 represents the first character in the second line of mode 2 for this particular mode. Memory location DISMEM + 2131 represents the second character, and so on up to DISMEM + 2149 for the twentieth character.
We know that POKEing the appropriate value into the appropriate location will cause the desired character to appear at the desired screen location. Since we already know how to determine the appropriate memory location, we now ask:
How do I calculate the appropriate value for a character?
It turns out that the value to poke for a given character corresponds to the order in which the character descriptions are stored in ROM (see "Designing Your Own Atari Character Sets" in the March 1981 issue of COMPUTE!). As a quick memory refresher:
|ATASCII VALUE||VALUE TO POKE|
For reverse characters, just add 128 to the value of the normal character.
My brain Is In hibernation; how do I convert a character string to its appropriate values?
I'll leave you with the folowing self-explanatory subroutine that will take the (predefined) character string PRNTME$ and the starting memory location STARTHERE (also predefined and equal to DISMEM + offset) and POKE PRNTME$ into the appropriate (love that word!) memory locations. Enjoy!
30000 REM /*This loop will act on each character in PRINTME$*/ 30010 FOR ME = 1 TO LEN (PRNTME$) 30020 REM /* Find ATASCII value of character*/ 30030 VALUE = ASC (PRNTME$(ME, ME)) 30040 REM /*Subtract 128 temporarily if it's a reverse character*/ 30050 VALUE = VALUE - 128* (VALUE >127) : = REM /* see note below*/ 30060 REM /* Make the appropriate value adjustments*/ 30070 VALUE = VALUE + 64 * (VALUE <32) - 32 * (VALUE > 31 AND VALUE < 96) 30080 REM /* Convert back to reverse if necessary*/ 30090 VALUE = VALUE + 128* (ASC(PRNTME$(ME, ME))>127) 30100 POKE STARTHERE + ME - 1, VALUE : REM /*remember, ME Starts at 0, not 1*/ 30110 ? VALUE 30120 REM /* Go to next character */ 30130 NEXT ME 30140 REM /*All done, say goodbye*/ 30150 RETURN
Note that (condition) equals 1 if the condition is true, 0 if it's not. Thus, X = 126 : PRINT (X = 126) : PRINT (X = 127) will print a 1 followed by a 0.
SPECIAL CORRECTION NOTE
The original article, "Designing Your Own Atari Graphics Modes," was incorrect in that the graphics mode you use initially should be a full screen mode. In other words, if graphics mode six is the mode that uses the most memory out of the modes you will be mixing, you should use GRAPHICS 22, not GRAPHICS 6 (just add 16 to the mode number). In the example used in the article, line 10 should read:
10 GRAPHICS 17 and not 10 GRAPHICS 1
My apologies for any problems caused by this mistake.