Experiments with the Spectrum ROM Font
- MatGubbins
- Dynamite Dan
- Posts: 1239
- Joined: Mon Nov 13, 2017 11:45 am
- Location: Kent, UK
Re: Experiments with the Spectrum ROM Font
That is a great routine Tom.
Re: Experiments with the Spectrum ROM Font
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
Re: Experiments with the Spectrum ROM Font
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
Re: Experiments with the Spectrum ROM Font
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.
Like the clean look and the way it's all procedurally generated from the ROM without needing a new character set in RAM.
Cosmium
https://cosmium.itch.io/
https://cosmium.itch.io/
Re: Experiments with the Spectrum ROM Font
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?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
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
Re: Experiments with the Spectrum ROM Font
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?
Re: Experiments with the Spectrum ROM Font
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
Re: Experiments with the Spectrum ROM Font
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
Re: Experiments with the Spectrum ROM Font
I was able to repro this in basic (on a BBC micro as the Spectrum doesn't have bitwise operations) here:TomD wrote: ↑Mon May 16, 2022 1:38 pmAs 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.
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
Re: Experiments with the Spectrum ROM Font
Looks good, BBC Basic is amazingly powerful. Been looking at getting this working in Spectrum Basic via a FN() call but proving a challengeKweepa wrote: ↑Mon May 16, 2022 6:05 pmI was able to repro this in basic (on a BBC micro as the Spectrum doesn't have bitwise operations) here: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.
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
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
Re: Experiments with the Spectrum ROM Font
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
Re: Experiments with the Spectrum ROM Font
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.
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.
Re: Experiments with the Spectrum ROM Font
Slightly faster BASIC version (with a lookup table for consecutive bits):
Still way too slow for anything but a crap game competition entry...
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
Re: Experiments with the Spectrum ROM Font
I made a few changes and with a bit of help this routine is a bit smaller (70 bytes I think). It seems that it's really only necessary to detect two bits next to each other.
Code: Select all
device zxspectrum48
org $c000
drawtext:
ld hl,text
ld de,18432+(3*32) ; start pos
textloop:
ld a,(hl)
and a
ret z
push hl ; store text address
ld bc,$3C00 ; rom font
ld h,c
add a,a
ld l,a
add hl,hl
add hl,hl
add hl,bc
; keep screen address
push de
ld b,8
charloop:
ld a,(hl) ; value
ld c,a ; keep for later
;look for 2 contiguous bits
bitloop:
cp #C0
jr nc,twobits
add a,a
jr nz,bitloop
scf
jr secondline
twobits: ; found two bits together, display previous line
dec hl
ld c,(hl) ; get next line above instead
inc hl
secondline:
ld a,c
ld (de),a ; write
call linedown
ld a,(hl)
ld (de),a
call linedown
linedone:
inc hl ; next byte
djnz charloop
pop de
inc de
pop hl
inc hl
jr textloop
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
text:
defb "Loading ",0x22,"ChuckieEgg",0x22," Please Wait",0
savetap "bitfont.tap",drawtext
Re: Experiments with the Spectrum ROM Font
by the way, if you want to know if a number has two contiguous bits in BASIC, I think something like this will work. Apologies as I haven't written anything in BASIC for a very long time.
LET A=PEEK(charaddr)
LET B=0
FOR I=1 to 7
IF A>191 THEN LET B=1
LET A=A+A
if A>255 THEN LET A=A-256
NEXT I
what this does is check for a number > 191, which means the last two bits of A are set. It then shifts A to the left by doubling it and removing the carry. If there are two bits next to each other then sooner or later the number will be greater than 191.
...I think!
LET A=PEEK(charaddr)
LET B=0
FOR I=1 to 7
IF A>191 THEN LET B=1
LET A=A+A
if A>255 THEN LET A=A-256
NEXT I
what this does is check for a number > 191, which means the last two bits of A are set. It then shifts A to the left by doubling it and removing the carry. If there are two bits next to each other then sooner or later the number will be greater than 191.
...I think!
Re: Experiments with the Spectrum ROM Font
That is almost exactly what I did in the super slow version