Double buffering on the Spectrum

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Ralf
Manic Miner
Posts: 541
Joined: Mon Nov 13, 2017 11:59 am
Location: Poland

Re: Double buffering on the Spectrum

Post by Ralf » Tue Apr 17, 2018 11:05 am

Hi Giorgio! Welcome to the forums!

This discussion about floating bus is certainly very interesting.

I would have one advice to beginner programmers however. Don't mess with with floating bus ;) It's a rather advanced trick. Joffa games were generally a piece of quite sophisticated code.

A "normal", typical game did it this way:

1) It keeps a screen buffer somewhere in memory
2) It draws to this buffer as fast as it can but usually longer than one frame
3) When it's ready it copies the buffer to screen by series of LDI commands without any synchronisation with screen refresh

Copying buffer to screen may alone take more than one frame so some artifacts on screen may happen. And the final framerate was around 12.5 fls or so.

It all may sound very rough and crude but in practice it worked and the result was acceptable.
0 x

User avatar
Nomad
Manic Miner
Posts: 521
Joined: Thu Dec 28, 2017 12:38 pm

Re: Double buffering on the Spectrum

Post by Nomad » Tue Apr 17, 2018 12:06 pm

Did Joffa Smith ever talk about or write on how he wrote his games?
0 x

Ralf
Manic Miner
Posts: 541
Joined: Mon Nov 13, 2017 11:59 am
Location: Poland

Re: Double buffering on the Spectrum

Post by Ralf » Tue Apr 17, 2018 12:14 pm

Did Joffa Smith ever talk about or write on how he wrote his games?
He made some comments here and there but not very detailed.
In my opinion he was generally a very modest man. He would probably say you that all his tricks were nothing special and not worth to get excited about.
1 x

User avatar
Nomad
Manic Miner
Posts: 521
Joined: Thu Dec 28, 2017 12:38 pm

Re: Double buffering on the Spectrum

Post by Nomad » Tue Apr 17, 2018 12:37 pm

Kind of like an anti Ian Weatherburn then (personality wise). :lol:

One of the most frustrating things trying to find out about N.O.M.A.D was the main developer had left nothing behind about how he wrote the game. It was weird that for a guy that was so sure of his own genius that he didn't talk about his process more before he became An Hero after Canvas folded.
0 x

User avatar
Ast A. Moore
Manic Miner
Posts: 341
Joined: Mon Nov 13, 2017 3:16 pm

Re: Double buffering on the Spectrum

Post by Ast A. Moore » Tue Apr 17, 2018 1:51 pm

2 x
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.

User avatar
druellan
Berk
Posts: 19
Joined: Tue Apr 03, 2018 6:19 pm
Contact:

Re: Double buffering on the Spectrum

Post by druellan » Tue Apr 17, 2018 3:48 pm

Ralf wrote:
Tue Apr 17, 2018 12:14 pm
He made some comments here and there but not very detailed.
In my opinion he was generally a very modest man. He would probably say you that all his tricks were nothing special and not worth to get excited about.
Was Steve Wetherill also able to figure out the trick for SideWize?
0 x

Joefish
Microbot
Posts: 172
Joined: Tue Nov 14, 2017 10:26 am

Re: Double buffering on the Spectrum

Post by Joefish » Tue Apr 17, 2018 4:15 pm

Joffa did give some loose notes on how he did his scrolling, but they were such that you'd only really understand it if you tried to program it yourself. I had a few private exchanges with him and here are the basics that I gleaned. I didn't actually get anything from him about the floating bus, so I don't know when or where he used it. Much of what I understood was simply down to timing of the program code.

His general approach was for a 25fps update rate, which worked as follows:

1. Wait for an interrupt.
2. Do some pre-processing of various stuff. This is a delay whilst the raster reaches the first line of the screen, so could be using the floating bus. This may involve sorting the sprites into vertical order.
3. Redraw the scrolling level scenery line-by-line from the top down, just behind the raster. Any sprites are erased by this scenery wipe. This is inevitably slower than the raster so by the time it finishes, the raster will be well into the lower scoreboard, if not the lower border or even the next TV frame.
4. Draw the sprites as fast as possible, hopefully before the raster catches up with their positions - hence the vertical sorting earlier. Fully expect the next frame interrupt to occur while this is going on, if it hasn't already.
5. Make sound effects. Rig the system so the next interrupt breaks out of the sound routine and loops back to 2.

Sprites were generally only placeable at 2-pixel positions (4 pre-shifted frames horizontally, data stored in a left-right/right-left zig-zag form with masks and drawn two rows at a time). There were enough black-attribute columns either side for the screen to mask off sprites that went outside the scenery area.

For games, specifically:

Green Beret -
Used an 8-character high buffered strip that was pixel-scrolled horizontally, filled in at the edge from scenery data, and copied to the screen. Don't know if the scroll and copy were done simultaneously or if the scroll was done, then POP+PUSH used to copy it. The top third of the screen is simply erased. The rockets are made to protrude slightly higher into the empty sky by adding sprites to their tips.

Hysteria
Like Green Beret, used an 8-character high strip pixel-scrolled horizontally and copied to the screen. But some of the extra space was filled in by parallax patterns at the bottom of the screen. These are simply 16-bit values repeatedly PUSHed across the screen. Note how the sprites that are supposed to be sat on the background judder slightly as they move in 2-pixel resolution compared to the scenery's 1-pixel movement. Note also you can grab items off the background, though you're actually running along the strip of ground in front that's moving in 2-pixel steps.

Cobra
This one is more complicated - there is no background buffer; the scenery is redrawn from scratch each frame. There are a very limited number of scenic blocks, but it's actually quicker than a scroll+copy. Note also that the scenery now scrolls in 2-pixel steps.
The pre-shifted scenery blocks are loaded into the registers AF, BC, DE and HL then the scenery is drawn by a series of PUSHes, PUSHing the relevant pattern onto the screen at that point. It's wasteful as a scrolling pattern may be half-in and half-out of a character position. So the patterns for solid platforms might be:

AF = empty space
BC = start of platform
DE = continuous platform
HL = end of platform

But before this happens, the program must first re-write the list of PUSH instructions to match the level data. The PUSH list for each row of scenery blocks is re-used to draw all 16 pixel rows. It only has to POP four registers to fetch the scenery patterns for an entire pixel row, so it's quicker that using POP+PUSH to copy a row of data (just as many PUSHes, but fewer POPs).

The scroll can also draw things one-character over, so it only needs scenery pre-shifted to 4 positions (to cover each pattern moving across 8 pixels, not 16). The blacked-off borders either side of the screen are uneven; there's an extra character on one side to hide the scenery redraw moving about, as well as any sprite overlap.

It can have a different set of patterns on each row of the screen, and because of the character-position adjustment it can have either:
- one pattern that can be repeated to any length (e.g. platforms which need 3 pre-shifted patterns to start, repeat and end)
- or 3 separate patterns of a narrow upright object (e.g. pipes up to 10 pixels wide, which always just fit within one 16 pixel wide pre-shifted block)
- or one platform that must start and end within 24 pixels and one narrow upright object.

Finally, there's a faster parallax bit at the bottom of the screen drawn by just PUSHing a 16-bit wide pattern right across the screen. This is programmed to occur twice per game cycle. The result is that this part scrolls at 50fps, making everything seem a bit smoother.
3 x

User avatar
Ast A. Moore
Manic Miner
Posts: 341
Joined: Mon Nov 13, 2017 3:16 pm

Re: Double buffering on the Spectrum

Post by Ast A. Moore » Tue Apr 17, 2018 5:59 pm

Joefish wrote:
Tue Apr 17, 2018 4:15 pm
I didn't actually get anything from him about the floating bus, so I don't know when or where he used it.
I think he only used it in Cobra and Terra Cresta. Both use the same code:

Code: Select all

	ld bc,$3f28	;Cobra
1$	ld a,c
	in a,($ff)
	cp b
	jr nc,1$
	
	ld c,$28	;Terra Cresta
	ld b,$3f
1$	ld a,c
	in a,($ff)
	cp b
	jr nc,1$
druellan wrote:
Tue Apr 17, 2018 3:48 pm
Ralf wrote:
Tue Apr 17, 2018 12:14 pm
He made some comments here and there but not very detailed.
In my opinion he was generally a very modest man. He would probably say you that all his tricks were nothing special and not worth to get excited about.
Was Steve Wetherill also able to figure out the trick for SideWize?
Yes, he was. Sidewize was never re-released, though. So it hangs on a +2A. Steve’s code is as follows:

Code: Select all

	ld bc,$40ff
	ld e,$40	;BRIGHT BLACK INK on BLACK PAPER
sync	ld a,r		;padding instruction
	in a,(c)
	cp e
	jp nz,sync
Curiously enough, in his blog post he admits that he doesn’t remember wha the LD A,R instruction does and speculates that it’s “some self-modifying code to conditionally branch on the state of the Z80 parity flag.” :D
0 x
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.

Joefish
Microbot
Posts: 172
Joined: Tue Nov 14, 2017 10:26 am

Re: Double buffering on the Spectrum

Post by Joefish » Tue Apr 17, 2018 6:07 pm

I didn't fully appreciate that Sidewize / Crosswize run at 50fps.
That's a lot of scenery and sprites being redrawn. I can see that Sidewize uses a block of scenery that repeats several times across the screen, and I know Crosswize multi-loads, so it's probably not being super-efficient with memory, but nevertheless 50fps is quite an achievement!
0 x

User avatar
Ast A. Moore
Manic Miner
Posts: 341
Joined: Mon Nov 13, 2017 3:16 pm

Re: Double buffering on the Spectrum

Post by Ast A. Moore » Tue Apr 17, 2018 6:17 pm

Joefish wrote:
Tue Apr 17, 2018 6:07 pm
I didn't fully appreciate that Sidewize / Crosswize run at 50fps.
That's a lot of scenery and sprites being redrawn. I can see that Sidewize uses a block of scenery that repeats several times across the screen, and I know Crosswize multi-loads, so it's probably not being super-efficient with memory, but nevertheless 50fps is quite an achievement!
Yes, Sidewize was pretty impressive from a technical standpoint. Incidentally, I only learned about it a couple of years ago. It'd somehow slipped under my radar back in the day.

What I miss the most in Spectrum games today are ducks. Joffa really knew how to cook ’em. :lol:
0 x
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.

Post Reply