Experiments with the Spectrum ROM Font

The place for codemasters or beginners to talk about programming any language for the Spectrum.
User avatar
TomD
Manic Miner
Posts: 377
Joined: Tue Nov 13, 2018 9:47 am
Location: Leeds UK
Contact:

Experiments with the Spectrum ROM Font

Post by TomD »

As part of adding a loading message to my utilities (in place of a loading screen) I wanted the text to use something a little larger than the standard ROM font, double height to be precise. I also didn't want the code to be large which a custom font would've needed due to the graphics so I looked into manipulating the ROM charset. I've written code in the past that literally doubles the pixels vertically but for this I wanted something a little more sophisticated :-)

Anyway after a lot of messing about and some very weird and wonderful results I came up with the following which I'm happy with. It supports the full charset, lower and upper case etc... and is pretty small in size as it doesn't need any graphics storing.

Not sure if anybody has already done this or a variation (very likely) but thought would be good to share in case anybody wants to use it.

Image

Total code size is <100bytes minus the text and obviously not including the ROM charset.

Code: Select all

_main:
	ld hl,_txt
	ld de,18432+(3*32) ; start pos
_loop:	
	ld a,(hl) ; get text -> A=0x41
	sub 0x20
	ret c
	push hl
	ld l,a
	ld h,0
	add hl,hl ; x2
	add hl,hl ; x4
	add hl,hl ; x8
	ld bc,0x3d00	; rom font
	add hl,bc	; hl now correct graphic
; plot font
	push de
	ld b,8
	ld c,b	; c=8
_pltloop:
	ld a,(hl)
	inc hl
	ld (de),a
	inc d
; what to plot on 2nd line
	push bc
	push de
	push hl
	ld d,a
	ld b,c	; b=8
	ld e,(hl)	
	xor a
	ld c,a
	ld l,1
	ld h,1
_testloop:
	rrc d
	jr nc,_testloop100
	ex af,af'
	ld a,c
	add a,l
	ld c,a
	ex af,af'
	inc l	; cumulative +1
	jr _testloop110
_testloop100:
	ld l,1	; reset cumulative counter
_testloop110:
	rrc e
	jr nc,_testloop120
	add a,h
	inc h
	jr _testloop120
_testloop120:
	ld h,1	; reset cumulative counter
_testloop130:
	djnz _testloop
	pop hl
	cp c
	ld a,d
	jr nc,_plotc
	ld a,(hl)
_plotc:
	pop de
	pop bc
	ld (de),a
	inc d
; over char line?
	ld a,d
	and %00000111
	jr nz,_inchar
	ld a,e
	add a,32
	ld e,a
	ld a,d
	sub c	; sub 8
	ld d,a
_inchar:
	djnz _pltloop
; onto next
	pop de
	pop hl
	inc hl
	inc e
	jr _loop	
;	
_txt:
	defb "Loading ",0x22,"ChuckieEgg",0x22," Please Wait",0
Retro enthusiast and author of Flynn's Adventure in Bombland, The Order of Mazes & Maze Death Rally-X. Check them out at http://tomdalby.com
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Experiments with the Spectrum ROM Font

Post by Ast A. Moore »

Looks awesome!

I just had a quick look, and I like it a lot. Just a few (minor) optimizations:

1. This:

Code: Select all

	ld l,a
	ld h,0
	add hl,hl ; x2
	add hl,hl ; x4
	add hl,hl ; x8
can be replaced with this:

Code: Select all

	ld h,0
	add a,a
	ld l,a
	add hl,hl
	add hl,hl
making it quite a bit faster.

2. LD H,1/LD L,1 in pltloop could just be LD HL,$101

3. The instruction JR _testloop120 in testloop110 should probably be JR _testloop130
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
TomD
Manic Miner
Posts: 377
Joined: Tue Nov 13, 2018 9:47 am
Location: Leeds UK
Contact:

Re: Experiments with the Spectrum ROM Font

Post by TomD »

Ast A. Moore wrote: Fri May 13, 2022 1:05 pm 3. The instruction JR _testloop120 in testloop110 should probably be JR _testloop130
Great spot, looks like penalising the 2nd line didn't do anything so I've removed it and saved a few bytes. New code is now only 88bytes

Code: Select all

org 32179
_main:
	ld hl,_txt
	ld de,18432+(3*32) ; start pos
_loop:	
	ld a,(hl) ; get text -> A=0x41
	sub 0x20
	ret c
	push hl
	add a,a ; x2
	ld l,a
	ld h,0
	add hl,hl ; x4
	add hl,hl ; x8
	ld bc,0x3d00	; rom font
	add hl,bc	; hl now correct graphic
; plot font
	push de
	ld b,8
	ld c,b	; c=8
_pltloop:
	ld a,(hl)
	inc hl
	ld (de),a
	inc d
; what to plot on 2nd line
	push bc
	push de
	push hl
	ld d,a
	ld b,c	; b=8
	ld e,(hl)	
	xor a
	ld c,a
	ld l,1
_testloop:
	rrc d
	jr nc,_testloop100
	add a,l
	inc l	; penalty for continuous bits +1
	jr _testloop110
_testloop100:
	ld l,1	; reset cumulative counter
_testloop110:
	rrc e
	jr nc,_testloop120
	inc c
_testloop120:
	djnz _testloop
	pop hl
	cp c
	ld a,d
	jr z,_plotc
	jr c,_plotc	
	ld a,(hl)
_plotc:
	pop de
	pop bc
	ld (de),a
	inc d
; over char line?
	ld a,d
	and %00000111
	jr nz,_inchar
	ld a,e
	add a,32
	ld e,a
	ld a,d
	sub c	; sub 8
	ld d,a
_inchar:
	djnz _pltloop
; onto next
	pop de
	pop hl
	inc hl
	inc e
	jr _loop	
;	
_txt:
	defb "Loading ",0x22,"ChuckieEgg",0x22," Please Wait",0
Retro enthusiast and author of Flynn's Adventure in Bombland, The Order of Mazes & Maze Death Rally-X. Check them out at http://tomdalby.com
User avatar
luny
Manic Miner
Posts: 220
Joined: Wed Apr 20, 2022 8:25 am
Contact:

Re: Experiments with the Spectrum ROM Font

Post by luny »

Genius, I love the idea of only doubling certain row types. It looks really clean and crisp.
I code to live (Job) and I live to code (Retro). One of them has to give!
User avatar
spider
Dynamite Dan
Posts: 1099
Joined: Wed May 01, 2019 10:59 am
Location: Derby, UK
Contact:

Re: Experiments with the Spectrum ROM Font

Post by spider »

That is an excellent looking result. I've not tried it personally yet.

I am not hugely keen on the default font unfortunately (same for the CPC actually) , and various other ones I tried the only one that I found that looked decent was the JSW128 one as almost all the symbols, numbers and letters were very readable in both upper and lower case even when faced with a few pages of Basic, so I use that one now for my main 48 and 128 ROM on emulation:

Image

Image


Having said that the stuff you've posted as I've said looks well worth a go at! :D
User avatar
g0blinish
Manic Miner
Posts: 287
Joined: Sun Jun 17, 2018 2:54 pm

Re: Experiments with the Spectrum ROM Font

Post by g0blinish »

Image
User avatar
R-Tape
Site Admin
Posts: 6407
Joined: Thu Nov 09, 2017 11:46 am

Re: Experiments with the Spectrum ROM Font

Post by R-Tape »

Image

As the picture says really. In the past I've tried mucking about with properties of the ROM font, even line by line, but it always looked a shambles. This is really good, especially for about 100 bytes. With a simple 'next line' and 'print at', this will be really useful.
Timmy
Manic Miner
Posts: 229
Joined: Sat Apr 23, 2022 7:13 pm
Location: The Netherlands

Re: Experiments with the Spectrum ROM Font

Post by Timmy »

Impressive.

There's also MegaText in YS issue 21 and 35, if you just want to experiment with the Spectrum ROM Font.
highrise
Manic Miner
Posts: 300
Joined: Fri Mar 20, 2020 11:29 pm

Re: Experiments with the Spectrum ROM Font

Post by highrise »

nice work! One thing to add to this might be to 'embolden' it by shifting each byte one place to the left or right and overprinting, thus giving thicker lines. I think the ROM font is skinny enough to handle that quite well.
highrise
Manic Miner
Posts: 300
Joined: Fri Mar 20, 2020 11:29 pm

Re: Experiments with the Spectrum ROM Font

Post by highrise »

I added the following lines just after the byte is loaded using ld a,(hl)

ld a,(hl) ; original code
srl a ; added shift
or (hl) ; added overprint.

The result was quite interesting. Ignore the 'nonsense in basic' part, that's just me doing a rough and ready tap in sjasmplus.




Image
User avatar
MatGubbins
Dynamite Dan
Posts: 1239
Joined: Mon Nov 13, 2017 11:45 am
Location: Kent, UK

Re: Experiments with the Spectrum ROM Font

Post by MatGubbins »

That is a great routine Tom.
User avatar
g0blinish
Manic Miner
Posts: 287
Joined: Sun Jun 17, 2018 2:54 pm

Re: Experiments with the Spectrum ROM Font

Post by g0blinish »

Code: Select all

_loop:	
	ld a,(hl) ; get text -> A=0x41
	or a;sub 0x20
	ret z;ret c
	push hl
	add a,a ; x2
	ld l,a
	ld h,0
	add hl,hl ; x4
	add hl,hl ; x8
	ld bc,0x3C00	; rom font-32*8

User avatar
g0blinish
Manic Miner
Posts: 287
Joined: Sun Jun 17, 2018 2:54 pm

Re: Experiments with the Spectrum ROM Font

Post by g0blinish »

one optimisation:

Code: Select all

;works if A=0..127
 ld l,a
 add hl,hl
 ld h,$1E
 add hl,hl
 add hl,hl
User avatar
Cosmium
Microbot
Posts: 156
Joined: Tue Dec 04, 2018 10:20 pm
Location: USA

Re: Experiments with the Spectrum ROM Font

Post by Cosmium »

Very nice!

Like the clean look and the way it's all procedurally generated from the ROM without needing a new character set in RAM.
User avatar
TomD
Manic Miner
Posts: 377
Joined: Tue Nov 13, 2018 9:47 am
Location: Leeds UK
Contact:

Re: Experiments with the Spectrum ROM Font

Post by TomD »

g0blinish wrote: Sat May 14, 2022 1:49 pm one optimisation:

Code: Select all

;works if A=0..127
 ld l,a
 add hl,hl
 ld h,$1E
 add hl,hl
 add hl,hl
Couldn't get this to work, first thought the ld h,$1e was in the wrong place as it is half $3c so 2 adds after it would make by x4, but even moving it after the second add hl,hl didn't fix it. Wondering if I've missed something?
Retro enthusiast and author of Flynn's Adventure in Bombland, The Order of Mazes & Maze Death Rally-X. Check them out at http://tomdalby.com
User avatar
Joefish
Rick Dangerous
Posts: 2058
Joined: Tue Nov 14, 2017 10:26 am

Re: Experiments with the Spectrum ROM Font

Post by Joefish »

I like the look. Can you explain the algorithm? Is there some sort of clever adaptive function going on, rather than simply expanding a specific list of rows within each character?
User avatar
g0blinish
Manic Miner
Posts: 287
Joined: Sun Jun 17, 2018 2:54 pm

Re: Experiments with the Spectrum ROM Font

Post by g0blinish »

Cosmium wrote: Sat May 14, 2022 9:41 pm Very nice!

Like the clean look and the way it's all procedurally generated from the ROM without needing a new character set in RAM.
my mistake: ld h,$0F
User avatar
TomD
Manic Miner
Posts: 377
Joined: Tue Nov 13, 2018 9:47 am
Location: Leeds UK
Contact:

Re: Experiments with the Spectrum ROM Font

Post by TomD »

Joefish wrote: Mon May 16, 2022 12:03 pm I like the look. Can you explain the algorithm? Is there some sort of clever adaptive function going on, rather than simply expanding a specific list of rows within each character?
As it is doubling on the y-axis the algorithm plots the first byte as per the ROM, and then for the 2nd line (the double one) it checks the current byte against the next. It creates a simple weighting for the current byte which penalises continuous bits. This has the effect that horizontal lines carry a large penalty which favours the single bits which usually represent the vertical parts of the font.
Retro enthusiast and author of Flynn's Adventure in Bombland, The Order of Mazes & Maze Death Rally-X. Check them out at http://tomdalby.com
User avatar
TomD
Manic Miner
Posts: 377
Joined: Tue Nov 13, 2018 9:47 am
Location: Leeds UK
Contact:

Re: Experiments with the Spectrum ROM Font

Post by TomD »

g0blinish wrote: Mon May 16, 2022 12:26 pm
Cosmium wrote: Sat May 14, 2022 9:41 pm Very nice!

Like the clean look and the way it's all procedurally generated from the ROM without needing a new character set in RAM.
my mistake: ld h,$0F
Nice, down to 84bytes now (added an extra 2bytes to check for moving into next 3rd of screen so the text can be plotted on any char line now)

Code: Select all

_main:
	ld hl,_txt
	ld de,18432+(3*32) ; start pos
_loop:	
	ld a,(hl) ; get text -> A=0x41
	or a
	ret z
	push hl
	add a,a ; x2
	ld l,a
	ld h,0x0f
	add hl,hl ; x4
	add hl,hl ; x8
; plot font
	push de
	ld b,8
	ld c,b	; c=8
_pltloop:
	ld a,(hl)
	inc hl
	ld (de),a
	inc d
; what to plot on 2nd line
	push bc
	push de
	push hl
	ld d,a
	ld b,c	; b=8
	ld e,(hl)	
	xor a
	ld c,a
	ld l,a
_testloop:
	rrc d
	jr nc,_testloop100
	inc l	; penalty for continuous bits +1	
	add a,l
	jr _testloop110
_testloop100:
	ld l,0	; reset cumulative counter
_testloop110:
	rrc e
	jr nc,_testloop120
	inc c
_testloop120:
	djnz _testloop
	pop hl
	cp c
	ld a,d
	jr z,_plotc
	jr c,_plotc	
	ld a,(hl)
_plotc:
	pop de
	pop bc
	ld (de),a
	inc d
; over char line?
	ld a,d
	and %00000111
	jr nz,_inchar
	ld a,e
	add a,32
	ld e,a
	jr c,_inchar
	ld a,d
	sub c	; sub 8
	ld d,a
_inchar:
	djnz _pltloop
; onto next
	pop de
	pop hl
	inc hl
	inc e
	jr _loop	
;	
_txt:
	defb "Loading ",0x22,"ChuckieEgg",0x22," Please Wait",0
Retro enthusiast and author of Flynn's Adventure in Bombland, The Order of Mazes & Maze Death Rally-X. Check them out at http://tomdalby.com
User avatar
g0blinish
Manic Miner
Posts: 287
Joined: Sun Jun 17, 2018 2:54 pm

Re: Experiments with the Spectrum ROM Font

Post by g0blinish »

TomD wrote: Mon May 16, 2022 1:43 pm Nice, down to 84bytes now (added an extra 2bytes to check for moving into next 3rd of screen so the text can be plotted on any char line now)
-1 byte: add a,a instead or a
User avatar
Kweepa
Manic Miner
Posts: 311
Joined: Sat Feb 03, 2018 6:14 pm
Location: Albuquerque, New Mexico

Re: Experiments with the Spectrum ROM Font

Post by Kweepa »

TomD wrote: Mon May 16, 2022 1:38 pm
Joefish wrote: Mon May 16, 2022 12:03 pm I like the look. Can you explain the algorithm? Is there some sort of clever adaptive function going on, rather than simply expanding a specific list of rows within each character?
As it is doubling on the y-axis the algorithm plots the first byte as per the ROM, and then for the 2nd line (the double one) it checks the current byte against the next. It creates a simple weighting for the current byte which penalises continuous bits. This has the effect that horizontal lines carry a large penalty which favours the single bits which usually represent the vertical parts of the font.
I was able to repro this in basic (on a BBC micro as the Spectrum doesn't have bitwise operations) here:


Essentially:

Code: Select all

loop over lines
   if it's the first non-empty line
      print a blank line
   else
      either print the last line again if this line has three pixels in a row, or print the current line
   endif
   print the current line
User avatar
TomD
Manic Miner
Posts: 377
Joined: Tue Nov 13, 2018 9:47 am
Location: Leeds UK
Contact:

Re: Experiments with the Spectrum ROM Font

Post by TomD »

Kweepa wrote: Mon May 16, 2022 6:05 pm
TomD wrote: Mon May 16, 2022 1:38 pm

As it is doubling on the y-axis the algorithm plots the first byte as per the ROM, and then for the 2nd line (the double one) it checks the current byte against the next. It creates a simple weighting for the current byte which penalises continuous bits. This has the effect that horizontal lines carry a large penalty which favours the single bits which usually represent the vertical parts of the font.
I was able to repro this in basic (on a BBC micro as the Spectrum doesn't have bitwise operations) here:


Essentially:

Code: Select all

loop over lines
   if it's the first non-empty line
      print a blank line
   else
      either print the last line again if this line has three pixels in a row, or print the current line
   endif
   print the current line
Looks good, BBC Basic is amazingly powerful. Been looking at getting this working in Spectrum Basic via a FN() call but proving a challenge :-)
Retro enthusiast and author of Flynn's Adventure in Bombland, The Order of Mazes & Maze Death Rally-X. Check them out at http://tomdalby.com
User avatar
Kweepa
Manic Miner
Posts: 311
Joined: Sat Feb 03, 2018 6:14 pm
Location: Albuquerque, New Mexico

Re: Experiments with the Spectrum ROM Font

Post by Kweepa »

Super slow but:

Code: Select all

10 LET a$="Loading "+CHR$ 34+"ChuckieEgg"+CHR$ 34+" Please Wait"
20 FOR i=1 TO LEN a$: LET q=15360+8* CODE a$(i): LET e=0: LET t=0: FOR k=0 TO 1: LET q=q+4*k: FOR b=0 TO 3: LET d=PEEK (q+b): LET n=0: LET m=d: FOR f=0 TO 5: IF m>=192 THEN LET n=1: LET f=5
30 IF m>=128 THEN LET m=m-128
40 LET m=m+m: NEXT f: IF n=0 THEN LET e=t*d
50 LET r=USR "a"+b+b: POKE r,e: POKE r+1,d: LET e=d: IF e>0 THEN LET t=1
60 NEXT b: PRINT AT 5+k,i-1;"\a": NEXT k: NEXT i
highrise
Manic Miner
Posts: 300
Joined: Fri Mar 20, 2020 11:29 pm

Re: Experiments with the Spectrum ROM Font

Post by highrise »

This got me quite intrigued as to how maybe the algorithm could be tweaked. I thought about this simple formula:

look at the current byte of the char, and check for two contiguous bits. If this occurs, then don't repeat for the second line, but instead grab the next byte down.

the char routine looks like this:

charloop:
ld a,(hl) ; value
ld c,a ; keep for later
ld (de),a ; write
call linedown
ld a,c
call bitcounter
cp 2
jr nz,secondline
inc hl
ld c,(hl) ; get next line down instead
dec hl
secondline:
ld a,c
ld (de),a
call linedown
inc hl ; next byte
djnz charloop

Line down is a typical one pixel down routine:

linedown:
inc d ; one line down
ld a,d
and 7
ret nz
ld a,e ; else add 32
add a,32
ld e,a
ret c
ld a,d ; else sub 8 from h
sub 8
ld d,a
ret

and finally, to check for two contiguous bits, which I think can be improved. It returns a value in c of 0,1 or 2.

bitcounter:
push bc
ld bc,$800 ; 8 lines, bit counter at zero
bitcount:
rrca ; check for carry
jr nc,skipbit ; no carry
; carried so increase c
inc c
bit 1,c ; hit 2 bits?
jr nz,done ; yes, return
jr nextbit ; else carry on but don't reset c
skipbit: ld c,0 ; reset counter at no carry
nextbit:
djnz bitcount
done: ld a,c
pop bc
ret

it's not quite right but could perhaps be improved on.


Image
User avatar
Kweepa
Manic Miner
Posts: 311
Joined: Sat Feb 03, 2018 6:14 pm
Location: Albuquerque, New Mexico

Re: Experiments with the Spectrum ROM Font

Post by Kweepa »

Slightly faster BASIC version (with a lookup table for consecutive bits):

Code: Select all

10 LET a$="Loading "+CHR$ 34+"ChuckieEgg"+CHR$ 34+" Please Wait"
20 DIM n(256): FOR i=1 TO 21: READ x: FOR j=0 TO 2+(i<14): LET n(x+j)=1: NEXT j: NEXT i: DATA 1,9,17,33,41,65,73,81,129,137,145,161,169,5,21,37,69,85,133,149,165
30 LET u=USR "a": FOR i=1 TO LEN a$: LET q=15360+8* CODE a$(i): LET e=0: LET t=0: FOR k=0 TO 1: FOR b=0 TO 3: LET d=PEEK (q+b): LET n=n(d+1)
40 IF n=1 THEN LET e=t*d
50 LET r=u+b+b: POKE r,e: POKE r+1,d: LET e=d: IF e>0 THEN LET t=1
60 NEXT b: PRINT AT 5+k,i-1;"\a": LET q=q+4: NEXT k: NEXT i
Still way too slow for anything but a crap game competition entry...
Post Reply