Let’s Cook up a Faster Graphic Enlarger for the ZX81
Time to create a new recipe for my old ZX81 graphic program.
I haven’t had much time for programming the last few months. To get back into things, I decided to take an old BASIC program of mine and rewrite it. Thinking about what to convert, my mind immediately went to Enlarger. It was a rather slow animation demo that could use an update.
# Spoiled food.
The original Enlarger was a straight forward program. It leveraged a pair of arrays to enlarge a graphic image. The first, the image, acts as the base. The second, the screen, act as intermediate screen storage. In the middle is a simple loop.
As I’ve discussed before, the looping algorithm is rather simple. It treats the array like a copy of the screen. The routine walks the first 16 characters of each line and doubles it in both directions. It then skips down and does the same for each line. It isn’t very optimized, but it works.
The biggest problem though, is that the routine is very slow. I wrapped the loop in a
FAST routine, but that didn’t improve things much. It takes quite a bit of time to compute each screen as it iterates over each of the 176 characters. The floating point math takes a good amount of compute. The slows down the program considerable.
When I shared enlarger back in 2013, I knew I could do better. At that time, I wrote a modified version that I saved each of the screens in an array. This allowed me to print each in succession. That routine is quite fast as it only has to print each frame of the animation to the screen. But, it consumes a lot of memory.
# Starting with a good base.
For the assembly version, I started with the BASIC listing and wrapped it in machine code. The program is mostly text, which I converted into data blocks. After adding a print routine, I soon had a very fast program that looked identical to the original.
For the enlarge part, I used the double buffer concept from my Picture In Motion code. The screen would be the starting array. With it, I would enlarge each of the characters into a second data buffer. After the routine finished, I would copy it to the screen location to complete the process. After a few tests, I had the wrapper code done.
# Adding a little hot sauce.
Now for the hard part—the assembly version of the enlarge routine. To start, I assume I’m expanding from the left edge. That means I go 16 across for 11 rows down. To do that, I made two loops, one for the rows and one for the columns. Between the two, I would walk the part of the screen I needed to enlarge.
Although this mimics the BASIC code, it is much simpler. Here, I don’t have to deal with any major calculations or array splicing. The math is straight forward, even if it didn’t make debugging any easier.
Although I was using basic integer math, I kept miscalculating the pointers. Part of the problem is that the ZX81 screen has newlines in it. Those aren’t usually an issue, but I had the counts off causing me to overwrite them. Messing up a newline causes some rather interesting screen effects. This made it hard to check my numbers. As such, it took me longer to debug than any of the rest of the program.
Finally, I got the routine working and had everything tested. Wow, was it fast! The display was very smooth due to the double buffer and looked great. I ended up adding some delay to make it easier to see each of the five frames. At this point the program was functional, but I wasn’t done yet.
# Adding a little garnish.
Outside of speed, at this point the assembly version looked the like the original. It did lose the jarring display issues caused by using
FAST mode. But, I was still using a pause command which caused the screen to bounce. I fixed it by replacing my use of pause. For that, I grabbed the delay routine from my Gem Quest game.
Although it worked, it lacked a few things. For one, you couldn’t break out of the program. To compensate, I added in a key check routine. This allowed the user to press space and break out, matching how BASIC would work. I had done something similar in z80 Digital Rain, but that routine would exit on any key press. It also had a side effect of leaking the key pressed to the command line.
To get the functionality I wanted, I did a keyboard read. This let me react to what key you pressed. As a bonus, it had the advantage of allowing me to break out of the delay if you pressed any key other than SPACE. This mimicked the
PAUSE command without the frame jump.
To fix the key leak, which also effected of skipping parts of the animation, I added a wait. It was a simple routine I’d used before to ensure the user had lifted their finger from the keyboard. With that in place, the program was complete.
# Plating for presentation.
Although done, I couldn’t stop here with a copy of the BASIC program. Since I had plenty of memory now, I decided to add in a couple more pictures to enlarge. This made the program a bit more interesting, showcasing assembly’s advantages.
The first image was a modified version of the moon with added craters. I used the checkerboard character to show that you don’t have to stick to the fill characters. This is true for both versions. I had chosen a space and filled space to make it look decent as it expanded. Here, using a different character made the moon look more interesting.
For the second image, I went a different direction by making a bee. I added some striped patterns using checkerboard again. I thought about using some other character, the algorithm doesn’t care. But filled blocks seemed to work best.
# Could use a bit more salt.
With all that said, the program works great and I have some nice routines I can reuse in other programs. The enlarger itself is less useful. I could make it more useful by allowing you to expand from different screen positions. This would allow for more creative uses.
Adding a shrink routine would be another option. That is a bit tough as I’d need some way to restore detail. To make that work I would need to have a data routine and the program would be a lot more complex. I actually did 8 or so years later in a college graphics class.
Summing everything up, Enlarger ASM was a fun little program to write. Like the program says, I’d like to make something spectacular with it someday. But for now, I’ll enjoy the faster routine and let the future develop as it will.