This is a demo for the BBC Micro which smoothly scrolls large, (kinda!) anti-aliased text across the screen at 50fps. If you've got an Econet then it can scroll the message across multiple screens.
The program is mostly implemented in 6502 assembly language with a menu system written in BBC BASIC.
Econet.Jumbo.Text.Scroller.Demo.mp4
Grab jumbo.ssd
from the Releases page and load onto your Beeb using your storage solution of choice.
The SSD is bootable so shift+BREAK should do the trick to kick off the menu or alternatively:
CHAIN "MENU"
Choose the standalone option if you're running on a single machine, supply a message and away you go.
If you're lucky enough to have a functioning Econet then selecting this option prompts you to enter the station numbers. The machine on which the menu is running (the "leader") is assumed to be the rightmost machine and you should enter the Econet station numbers of the other "follower" machines from right-to-left.
Ensure that you have BeebAsm in your PATH and execute make.sh
to generate a jumbo.ssd
disk image.
The drawing of the text is handled by render.asm
.
First, get_char_ptr_for_ascii
is used to look up the character to be drawn in the OS. This is represented as 8 bytes, one for each row; each bit within a row byte represents a pixel within that row. A filled-in pixel is a 1
and a "hole" is a 0
. Then 8 pixels are plotted on-screen for each filled-in pixel in the source character, turning the characters into 64x64 pixels:
Hmmm... a bit lumpy. To improve matters, some extra processing is done (in print_custom_infill_char
) when a hole pixel is found in the source character: the pixels immediately around it at each of the four compass points are evaluated. Where two lines appear to be intersecting, a little infill lump is drawn. Consider where the two lines of a letter 'L' meet: just inside there, the pixel to the left and the one below will be 1
and so we will draw an infill to the bottom-left. print_anti_alias_corners
takes the infill flags built up by print_custom_infill_char
and uses them to look up a custom character in tables.asm
(note the 1
s at the bottom-left):
.anti_alias_char8 ; BL/BR/TR/TL == 1000
EQUB %00000000
EQUB %00000000
EQUB %00000000
EQUB %00000000
EQUB %00000000
EQUB %00000000
EQUB %11000000
EQUB %11000000
Our 64x64 characters now look like this:
This app runs in screen mode 2 which is 160x256 pixels (20x32 characters). Each byte in screen memory describes two pixels (with the four bits per pixel giving a palette of 8 colours). It starts at &3000
and ends at &7fff
. By adding one to the start address of screen memory in the CRTC, the whole screen appears to move left by 2 pixels instantly without needing to do any memory copying. This is great because the Beeb doesn't have any blitting capability.
So all we need to do is fill in the 2 pixels just revealed by the scroll. The challenge is to do this quickly enough to fit within the vertical blanking interval in order to have a nice, smooth animation and to avoid "tearing" artefacts. render.asm
is therefore optimised to only draw a vertical slice of the character being scrolled in and scroll.asm
copies this in from the offscreen buffer to the screen. This has the additional advantage of keeping the offscreen buffer small (64 bytes).
Two separate pointers scroll_ptr
and dest_ptr
are maintained to keep track of the current scroll position (start of video memory) and where we're writing to (just to the right of the screen), respectively. When these advance past the end of video memory, they wrap back to the start. Thus scrolling can continue indefinitely, although the BASIC launcher currently imposes a limit of 254 chars to the size of the message.
The leader sends a copy of the program — including the message to be scrolled — to each follower in turn using an Econet POKE
operation. A JSR
operation then causes the follower to jump to the entrypoint of the app where it sits waiting for a broadcast. Once the leader has prepared all followers (upto 253 of them!), a single Econet TRANSMIT
operation to the broadcast address &00
kicks off the action in perfect synchronisation!
In order to give the effect of text moving from one screen to another, the leader starts scrolling immediately but the first follower, placed immediately to the left of the leader, delays the start of its scroll by the time it takes for the text to cross the leader's screen. The second follower is delayed by two screen scroll periods, the third by three and so on.
The process is illustrated in the following sequence diagram:
- Alex Nichol from King's School Worcester who wrote something very similar in the early 90s — this app is a tribute! Get in touch, dude.
- Kieran Connell for his excellent video on programming the CRTC, including how to do scrolling: https://www.youtube.com/watch?v=dbGRFUNARjw
- Demo music by Music Unlimited from Pixabay