Going into Action! with Atari XL/XE – Part 2 – Graphics
If you are following this series of articles, you could be thinking right now: “What a jump! From a Hello World to Graphics in one article!?”. Yes, you are right. After fiddling a bit with more Action! and reading some of the user’s guides talking about programming structures, variables, loops, etc… I found that following the same sequence here wouldn’t make much sense. People would just read the original manuals, which are excellent.
If you missed the first article, take a look here.
My approach in this tag-along series will be moving fast and talking about new things as we need them. I hope this way makes the reading more interesting while it would still help programmers to start with this language and non-programmers to learn something.
Graphics – Knowing the hardware will make you stronger!
I come to the conclusion that to be a good Atari 8-bit developer, one needs to know Atari hardware and as an extension, its memory mapping, at least to a point where they can help you understand how things are implemented. The good (and the bad) with the old 8-bit machines is that the operating system and the programming languages (usually BASIC and Assembler) reflect in its commands how the hardware work with little or no abstraction between the bare-metal and the user. In comparison, the computer you are reading this has a universe of software separating you from the CPU – just imagine if to do something you have to know the intricacies of how your GPU draws a polygon, for example!
Atari 8-bit computers provide a myriad of graphic modes, with different resolutions and the number of simultaneous colours. I decided to focus solely on graphic mode 7, which is one of the most popular because it offers a nice compromise between resolution, number of colours and memory usage.
The graphics mode 7 allows a 160×96 pixels in full screen and with four simultaneous colour, including the background one. How to set these colours is what is very confusing, mostly because the graphics commands follow how the hardware works (turning on and off bits here and there, etc).
The Atari will encode the actual colour definitions (hue and luminance) in five colour registers (0 to 4), which you can set at will. Each pixel on the screen will have two bits that will point to one of the colour registers’ values. The registers zero to two will hold the information of the three foreground colours, the fifth register contains the background colour definition, and the colour register 3 is not used because it is only used in text modes 1 and 2. That’s why a graphics mode, like mode 7, can have up to three foreground colours and one background colour.
A good way to understand the colour register concept is to picture something like this: if you set a colour register to yellow and tell the Atari that the next pixels plotted on the screen will use that colour register, all these pixels will be yellow – not a surprise here. However, if you change the same colour register to blue, all those pixels that were plotted yellow will become blue in the blink of the eye. In other words, the graphics on the screen contain a reference to what colour register they are using, not the colour itself.
Note: Color Registers and Colours have different behaviours depending on the text or graphic mode used.
To show the very basic use of colour registers and colours, I created this BASIC program that plots a Z on the screen using four different colours:
10 GRAPHICS 7+16
20 SETCOLOR 0,4,8:REM USE COLOR 1 (PINK)
22 SETCOLOR 1,7,4:REM USE COLOR 2 (BLUE)
24 SETCOLOR 2,0,14:REM USE COLOR 3 (WHITE)
26 SETCOLOR 4,7,8:REM BCKGROUND (LIGHT BLUE)
30 COLOR 1 ; tell the program the next commands will use color register 1
40 PLOT 10,10
50 DRAWTO 149,10
60 COLOR 2 ; tell the program the next commands will use color register 2
70 DRAWTO 10,85
80 COLOR 3 ; tell the program the next commands will use color register 3
90 DRAWTO 149,85
100 FOR I=1 TO 1000:NEXT I
110 GRAPHICS 0
Program explanation:
- Line 10: sets the graphic mode 7 (when you add 16 you set it to use the full screen)
- Lines 20-26: set colours for each one of the four colour registers (we skip #3)
- Line 30: Says all graphic commands following the COLOR command will be set using the colour specified in the colour register 1
- Line 40-50: Plots a pixel at position 10,10 and draw the first horizontal line from 10,10 to 149,10 (0,0 position is at the top left corner of the screen)
- Line 60-70: Change the “active” colour to the one specified in colour register 2 and plot the diagonal line
- Line 80-90: Change the “active” colour to the one specified in colour register 2 and plot the bottom line
- Line 100: Just using an empty loop to add a pause before going back to graphics mode 0, the default Atari text mode
Of course, we are not here to learn BASIC, but this simple program is very easy to follow even for people that are not programmers and my objective here is to show what I’ve learned about the graphics mode 7 and how to set specific colours. Maybe the only explanation needed there is the DRAWTO command which draws a line. The coordinates specified for the DRAWTO is the end position. The initial position is wherever the last pixel was plotted before – that’s why we have first a PLOT 10,10, to make sure we have a starting point. You can see that clearly when the program runs.
If you pay attention to the code, you will notice that the background is set using SETCOLOR 4,7,8 but we don’t have a correspondent COLOR 4 anywhere in the code. The explanation is that because color register 4 is used exclusively for the background colour when you set the colour register, the background colour immediately assumes that colour.
Action!
My next step was to convert the program above to Action!. Thankfully, the Action! language includes commands (aka functions) that mimic the BASIC ones very close. This is what I came up with:
proc init()
CARD I
GRAPHICS(7+16)
SETCOLOR(0,4,8) ;REM USE COLOR 1 (PINK)
SETCOLOR(1,7,4) ;REM USE COLOR 2 (BLUE)
SETCOLOR(2,0,14) ;REM USE COLOR 3 (WHITE)
SETCOLOR(4,7,8) ;REM BCKGROUND (LIGHT BLUE)
COLOR=1
PLOT(10,10)
DRAWTO(149,10)
COLOR=2
DRAWTO(10,85)
COLOR(3)
DRAWTO(149,85)
FOR I=1 TO 60000
DO
; nothing inside this loop!
OD
GRAPHICS(0)
return
If you ignore the “CARD I” at the beginning of the program, you can see that BASIC and Action! in this program are very similar, with some differences:
- GRAPHICS, SETCOLOR, PLOT, and DRAWTO are procedures (or functions) and Action! demands parenthesis to enclose the parameters you are passing to these procedures.
- The semi-colon “;” symbol indicates that everything that follows it is a remark (same as REM in BASIC) and it is ignored by the compiler – its sole purpose is to document the code.
- The loop command loops more times (32767 vs. 1000) than the BASIC program. This is necessary because Action! is much faster and only 1000 turns would finish the program before your eyes could register the drawing on screen!
- The loop command needs the DO…OD block to enclose all commands that will be repeated – in this case, since it is an empty loop, we added a little note there, for clarity’s sake.
- COLOR is a built-in variable (as opposed as a command in BASIC) and that’s why we are using the “=” there. When we have COLOR=1, it means “set the value 1 to the variable COLOR” – Although there is a difference in how it is implemented, the effect is the same in both languages.
Variables!
The “CARD I” at the beginning of the program shows one of the big differences between Action! and BASIC. While in BASIC you can simply start using a variable whenever you need one, in Action! you have to declare them at the top of your procedure before using it. To prove that, add a “;” in front of the variable declaration in the program above, compile and run it again ( ;CARD I ). Without the declaration, action will display an error message:
In Action! you can have three basic data types:
- BYTE: 8-bits, can hold numbers from 0 to 255
- INT: 16-bits signed, can hold numbers from -32768 to +32767
- CARD: 16-bits unsigned, can hold numbers from 0 to 65535
As you can see, we cannot assign any values to variables. We have to follow what the data type let us put in the variable. If you assign a number that goes beyond (or below) the boundaries of a variable, Action! won’t complain – it will simply rotate the number to the opposite boundary limit. It is probably easy to show:
proc Init()
byte b
b=0
printbe(b)
b=255
printbe(b)
b=256
printbe(b)
return
If you compile and run the program above you will have the numbers 0, 255 and 0 displayed on the screen. The last zero was assigned to the variable when you set it to 256. If you assign, for example, 257, the b will contain the value 1! In the same way, if you set the value to -1, the actual value set will be 255. If you know the binary notation, it is clear why that happens since a variable of type BYTE has only 8 bits to represent its numbers.
What about fractions?
Although the Atari has built-in support for fractional numbers, Action! doesn’t support them – it can only deal with integer numbers! Try this:
proc Init()
card b
b=10/3
printbe(b)
return
The displayed result will be 3, and not 3.3333333. This is a big limitation of the language but there are ways to overcome it! More to that later!
Speed
If you run both BASIC and Action! programs, it might come as a surprise to see that both programs will display the graphics at the same speed. The explanation is that the graphic commands just call ROM built-in functions to perform the tasks and they will run at maximum speed, no matter the language. The difference in speed can be seen in the empty for loop added at the end of the program, though.