Skip to content

Commit f982b61

Browse files
authored
Merge pull request #349 from boriel/feature/add_print_fzx
Add PRINTFZX lib
2 parents 949b0ee + 04dd08a commit f982b61

1 file changed

Lines changed: 307 additions & 0 deletions

File tree

library/printfzx.bas

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
'-----------------------------------------------------------------------------
2+
' FZX driver - Copyright (c) 2013 Einar Saukas
3+
' FZX format - Copyright (c) 2013 Andrew Owen
4+
' Ported to ZX Basic by Paul Fisher (@Britlion)
5+
' -----------------------------------------------------------------------------
6+
7+
8+
#ifndef __PRINTFZX__
9+
#define __PRINTFZX__
10+
11+
#pragma push(case_insensitive)
12+
#pragma case_insensitive = TRUE
13+
14+
15+
sub fastcall printFzxSetFontAddr(addr as Uinteger)
16+
ASM
17+
ld (__PRINTFZX_FONT_ADDR), hl
18+
END ASM
19+
end sub
20+
21+
22+
sub fastcall printFzxSetMargin(margin as ubyte)
23+
ASM
24+
ld (__PRINTFZX_MARGIN), a
25+
END ASM
26+
end sub
27+
28+
29+
sub fastcall printFzxAt(row as Ubyte, col as Ubyte)
30+
ASM
31+
push af
32+
ld a, 22
33+
call _printFzxChar
34+
pop af
35+
call _printFzxChar
36+
pop hl
37+
ex (sp), hl
38+
ld a, h
39+
jp _printFzxChar
40+
END ASM
41+
DIM dummy as Uinteger = @printFzxChar
42+
end sub
43+
44+
45+
sub printFzxStr(s as String)
46+
ASM
47+
PROC
48+
49+
LOCAL EXIT
50+
LOCAL LOOP
51+
52+
ld l, (ix + 4)
53+
ld h, (ix + 5)
54+
ld a, h
55+
or l
56+
jr z, EXIT
57+
ld c, (hl)
58+
inc hl
59+
ld b, (hl)
60+
61+
LOOP:
62+
ld a, b
63+
or c
64+
jr z, EXIT
65+
inc hl
66+
dec bc
67+
ld a, (hl)
68+
push hl
69+
push bc
70+
call _printFzxChar
71+
pop bc
72+
pop hl
73+
jr LOOP
74+
75+
EXIT:
76+
ENDP
77+
END ASM
78+
end sub
79+
80+
81+
sub fastcall printFzxChar(char as ubyte)
82+
ASM
83+
; -----------------------------------------------------------------------------
84+
; FZX driver - Copyright (c) 2013 Einar Saukas
85+
; FZX format - Copyright (c) 2013 Andrew Owen
86+
; -----------------------------------------------------------------------------
87+
PROC
88+
LOCAL GET_LIN
89+
LOCAL GET_COL
90+
LOCAL CHK_AT
91+
LOCAL CHK_CR
92+
LOCAL CHK_CHAR
93+
LOCAL UNDEF_CHAR
94+
LOCAL PRINT_CHAR
95+
LOCAL NARROW_CHAR
96+
LOCAL ON_SCREEN
97+
LOCAL MAIN_LOOP
98+
LOCAL SMC
99+
LOCAL ROTATE_PIXELS
100+
LOCAL NO_ROTATE
101+
LOCAL CHK_LOOP
102+
LOCAL WIDTH1
103+
LOCAL NEWLINE
104+
LOCAL EXIT
105+
106+
LOCAL P_FLAG
107+
LOCAL P_COL
108+
LOCAL P_LIN
109+
110+
LOCAL MARGIN
111+
MARGIN EQU 0 ; left margin (in pixels)
112+
113+
__PRINTFZX_FONT_ADDR EQU CHK_CR + 5
114+
__PRINTFZX_MARGIN EQU NEWLINE + 1
115+
116+
117+
; -----------------------------------------------------------------------------
118+
; ENTRY POINT #2 - PROPORTIONAL PRINT ROUTINE
119+
; -----------------------------------------------------------------------------
120+
ld hl, P_FLAG ; initial address of local variables
121+
dec (hl) ; check P_FLAG value by decrementing it
122+
jp m, CHK_AT ; expecting a regular character?
123+
jr z, GET_COL ; expecting the AT column?
124+
GET_LIN:
125+
cpl
126+
add a, 192 ; now A = 191 - char
127+
inc hl
128+
GET_COL:
129+
inc hl
130+
ld (hl), a
131+
ret
132+
CHK_AT:
133+
cp 22 ; specified keyword 'AT'?
134+
jr nz, CHK_CR
135+
ld (hl), 2 ; change P_FLAG to expect line value next time
136+
ret
137+
CHK_CR:
138+
push ix
139+
inc (hl) ; increment P_FLAG to restore previous value
140+
inc hl
141+
ld bc, 0 ; Points to FONT ADDRESS
142+
push bc
143+
pop ix
144+
cp 13
145+
jp z, NEWLINE
146+
CHK_CHAR:
147+
dec a ; now A = char - 1
148+
cp (ix+2) ; compare with lastchar
149+
jr nc, UNDEF_CHAR
150+
sub 31 ; now A = char - 32
151+
jr nc, PRINT_CHAR
152+
UNDEF_CHAR:
153+
ld a, '?'-32 ; print '?' instead of invalid character
154+
PRINT_CHAR:
155+
inc a ; now A = char - 31
156+
ld l, a
157+
ld h, 0
158+
ld d, h
159+
ld e, l
160+
add hl, hl
161+
add hl, de ; now HL = (char - 31) * 3
162+
add hl, bc ; now HL references offset/kern in char table
163+
ld e, (hl)
164+
inc hl
165+
ld a, (hl)
166+
and 63
167+
ld d, a ; now DE = offset
168+
169+
xor (hl)
170+
rlca
171+
rlca
172+
ld c, a ; now C = kern
173+
174+
push hl
175+
add hl, de
176+
dec hl ; now HL = char definition address
177+
ex (sp), hl ; now HL references offset/kern in char table
178+
inc hl ; now HL references shift/width in char table
179+
xor a
180+
rld ; now A = char shift
181+
push af
182+
rld ; now A = (width - 1)
183+
ld (WIDTH1+1), a
184+
cp 8 ; check if char width is larger than 8 bits
185+
rld ; restore char shift/width
186+
187+
ld de, $000e ; same as "LD C,0"
188+
jr c, NARROW_CHAR
189+
ld de, $234e ; same as "LD C,(HL)" and "INC HL"
190+
NARROW_CHAR:
191+
ld (SMC), de ; self-modify code to handle narrow/large chars
192+
193+
inc hl ; now HL references next char offset
194+
ld a, (hl) ; now A = LSB of next char offset
195+
add a, l
196+
ld e, a ; now E = LSB of next char definition address
197+
198+
ld hl, P_COL
199+
ld a, (hl)
200+
sub c ; move left number of pixels specified by kern
201+
jr nc, ON_SCREEN ; stop moving if it would fall outside screen
202+
xor a
203+
ON_SCREEN:
204+
ld (hl), a
205+
206+
ld a, (WIDTH1+1) ; now A = (width - 1)
207+
add a, (hl) ; now A = (width - 1) + column
208+
call c, NEWLINE ; if char width won't fit then move to new line
209+
210+
ld bc, (P_COL)
211+
ld a, 1
212+
sub (ix+0) ; now A = 1 - height
213+
add a, b ; now A = P_LIN - height + 1
214+
jp nc, $0c86 ; call routine REPORT-5 ("Out of screen")
215+
216+
pop af ; now A = shift
217+
218+
add a, 191 ; range 0-191
219+
call $22aa + 2 ; call PIXEL-ADD + 2 to calculate screen address
220+
ex af, af'
221+
; now A' = (col % 8)
222+
jr CHK_LOOP
223+
224+
MAIN_LOOP:
225+
ld d, (hl) ; now D = 1st byte from char definition grid
226+
inc hl ; next character definition
227+
SMC:
228+
ld c, (hl) ; now C = 2nd byte from char definition or zero
229+
inc hl ; (either "LD C,0" or "LD C,(HL)" + "INC HL")
230+
xor a ; now A = zero (since there's no 3rd byte)
231+
ex (sp), hl ; now HL = screen address
232+
233+
ex af, af'
234+
; now A = (col % 8), A' = 0
235+
jr z, NO_ROTATE
236+
ld b, a ; now B = (col % 8)
237+
ex af, af'
238+
; now A = 0, A' = (col % 8)
239+
ROTATE_PIXELS:
240+
srl d ; rotate right char definition grid in D,C,A
241+
rr c
242+
rra
243+
djnz ROTATE_PIXELS
244+
245+
NO_ROTATE:
246+
inc l
247+
inc l
248+
or (hl)
249+
ld (hl), a ; put A on screen
250+
dec l
251+
ld a, c
252+
or (hl)
253+
ld (hl), a ; put C on screen
254+
dec l
255+
ld a, d
256+
or (hl)
257+
ld (hl), a ; put D on screen
258+
259+
inc h ; move screen address by 1 pixel down
260+
ld a, h
261+
and 7
262+
jr nz, CHK_LOOP
263+
ld a, l
264+
sub -32
265+
ld l, a
266+
sbc a, a
267+
and -8
268+
add a, h
269+
ld h, a
270+
CHK_LOOP:
271+
ex (sp), hl ; now HL = char definition address
272+
ld a, l
273+
cp e ; check if reached next char definition address
274+
jr nz, MAIN_LOOP ; loop otherwise
275+
276+
pop hl ; discard screen address from stack
277+
ld hl, P_COL
278+
ld a, (hl) ; now A = column
279+
WIDTH1:
280+
add a, 0 ; now A = column + (width - 1)
281+
scf
282+
adc a, (ix+1) ; now A = column + width + tracking
283+
jr nc, EXIT ; if didn't fall outside the screen then exit
284+
NEWLINE:
285+
ld (hl), MARGIN ; move to initial column at left margin
286+
inc hl
287+
ld a, (hl) ; now A = line
288+
sub (ix+0) ; now A = line - height
289+
EXIT:
290+
ld (hl), a ; move down a few pixels specified by height
291+
pop ix
292+
ret
293+
294+
P_FLAG:
295+
defb 0
296+
P_COL:
297+
defb MARGIN
298+
P_LIN:
299+
defb 191
300+
ENDP
301+
; -----------------------------------------------------------------------------
302+
END ASM
303+
end sub
304+
305+
#pragma pop(case_insensitive)
306+
307+
#endif

0 commit comments

Comments
 (0)