1; m/c entry point for print string function
2; 02.2008 aralbrec, Sprite Pack v3.0
3; zx81 hi-res version
4
5PUBLIC SP1PrintString
6
7EXTERN sp1_GetUpdateStruct_callee, l_jpix
8EXTERN ASMDISP_SP1_GETUPDATESTRUCT_CALLEE
9EXTERN SP1V_UPDATELISTT, SP1V_DISPWIDTH
10EXTERN SP1V_TEMP_IX, SP1V_TEMP_AF
11
12; A sophisticated print string function
13;
14; The string to print is pointed at by HL and terminates with a 0 byte.
15; Characters are printed as background tiles
16; with the following special character codes understood:
17;
18; code     meaning
19; ----     -------
20;   0      terminate string
21;   1      NOP N* [other ports: logically AND into attribute mask N*]
22;   2      gotoy N* (goto y coordinate on same column)
23;   3      ywrap N*
24;   4      NOP N* [other ports: attribute mask N*]
25;   5      16-bit tile code follows W*
26;   6      gotox N* (goto x coordinate on same line)
27;   7      print string at address W* (like a subroutine call / macro for printstrings; see also 26,28)
28;   8      left
29;   9      right
30;  10      up
31;  11      down
32;  12      home (to top left of bounds rectangle)
33;  13      carriage return (move to start of next line in bounds rectangle)
34;  14      repeat N*
35;  15      endrepeat
36;  16      NOP N* [other ports: ink N*]
37;  17      NOP N* [other ports: paper N*]
38;  18      NOP N* [other ports: flash N*]
39;  19      NOP N* [other ports: bright N*]
40;  20      NOP N* [other ports: attribute N*]
41;  21      invalidate N*
42;  22      AT y(N*),x(N*) (relative to bounds rectangle)
43;  23      AT dy(N*), dx(N*)  (relative to current position in bounds rectangle)
44;  24      xwrap N*
45;  25      yinc N*
46;  26      push state
47;  27      escape, next char is literal not special code
48;  28      pop state
49;  29      transparent char
50;  30      NOP N* [other ports: logically OR into attribute mask N*]
51;  31      visit : call function pointed at by ix with current struct_sp1_update as parameter
52;
53; * N is a single byte parameter following the code.
54; * W is a 16-bit parameter following the code.
55;
56; All printing is done within a bounds rectangle.  No printing outside this
57; bounds rectangle will occur.
58;
59; enter:  HL = address of string to print
60;          E = flags (bit 0 = invalidate?, bit 1 = xwrap?, bit 2 = yinc?, bit3 = ywrap?)
61;          B = current x coordinate (relative to bounds rect IX)
62;          C = current y coordinate (relative to bounds rect IX)
63;    (    HL' = & tail struct sp1_update.ulist in invalidated list   ) loaded here, not entry condition
64;        DE' = current struct sp1_update *
65; (SP1V_TEMP_IX) = visit function
66;       IX+0 = row coordinate   \
67;       IX+1 = col coordinate   |  Bounds Rectangle
68;       IX+2 = width in chars   |  Must Fit On Screen
69;       IX+3 = height in chars  /
70; exit : same as enter
71; uses : all except af', iy
72;
73; The C API maintains a structure to retain the print state between calls.
74; Doing something similar from assembly language may be helpful.
75
76.SP1PrintString
77
78   exx
79   ld hl,(SP1V_UPDATELISTT)
80   ld bc,5
81   add hl,bc
82   exx
83
84   call psloop
85
86   exx
87   ld (hl),0
88   ld bc,-5
89   add hl,bc
90   ld (SP1V_UPDATELISTT),hl
91   exx
92   ret
93
94.psloop
95
96   ld a,(hl)
97   or a
98   ret z
99
100   inc hl
101   cp 32
102   jp nc, printable
103
104   ; here we have a special code [1,31]
105
106   push hl
107   ld d,a
108   add a,a                   ; get address of handler from jump table
109   ld h,jumptbl/256
110   add a,jumptbl%256
111   ld l,a
112   jp nc, nospill
113   inc h
114.nospill
115   ld a,(hl)
116   inc hl
117   ld h,(hl)
118   ld l,a
119   ld a,d                    ; restore A to code
120   ex (sp),hl
121   ret
122
123.jumptbl
124   defw NOP0, NOP1, codeGotoY, codeYWrap
125   defw NOP1, codeTC, codeGotoX, codePString
126   defw codeLeft, codeRight, codeUp, codeDown
127   defw codeHome, codeReturn, codeRepeat, codeEndRepeat
128   defw NOP1, NOP1, NOP1, NOP1
129   defw NOP1, codeInvalidate, codeAt, codeAtRel
130   defw codeXWrap, codeYInc, codePush, codeEscape
131   defw codePop, codeTransparent, NOP1, codeVisit
132
133.NOP1
134
135   inc hl              ; consume a single byte parameter
136
137   ; fall through to NOP0
138
139.NOP0
140
141   jp psloop           ; on to the next byte to interpret
142
143.codeVisit
144   ld a,b              ; only visit if inbounds
145   cp (ix+2)
146   jp nc, psloop
147   ld a,c
148   cp (ix+3)
149   jp nc, psloop
150
151   push ix
152   push bc
153   push de
154   push hl
155   exx
156   push hl
157   push de
158   ex de,hl
159   ld ix,(SP1V_TEMP_IX)
160   call l_jpix
161   pop de
162   pop hl
163   exx
164   pop hl
165   pop de
166   pop bc
167   pop ix
168   jp psloop
169
170.codeYWrap
171   ld a,(hl)           ; parameter following YWRAP (0/1)
172   inc hl
173   rra
174   jp nc, noywrap
175   set 3,e
176   jp psloop
177.noywrap
178   res 3,e
179   jp psloop
180
181.codeEscape
182   ld a,(hl)          ; char following ESCAPE
183   inc hl
184   jp printable
185
186.codePop
187   exx
188   pop de
189   exx
190   pop de
191   pop bc
192   jp psloop
193
194.codePush
195   push bc
196   push de
197   exx
198   push de
199   exx
200   jp psloop
201
202.codeYInc
203   ld a,(hl)           ; parameter following YINC (0/1)
204   inc hl
205   rra
206   jp nc, noywrap5
207   set 2,e
208   jp psloop
209.noywrap5
210   res 2,e
211   jp psloop
212
213.codeXWrap
214   ld a,(hl)           ; parameter following XWRAP (0/1)
215   inc hl
216   rra
217   jp nc, noxwrap
218   set 1,e
219   jp psloop
220.noxwrap
221   res 1,e
222   jp psloop
223
224.codeAtRel
225   ld a,(hl)
226   add a,c
227   ld c,a
228   inc hl
229   ld a,(hl)
230   add a,b
231   ld b,a
232   inc hl
233   jp computenewupdate
234
235.codeAt
236   ld c,(hl)
237   inc hl
238   ld b,(hl)
239   inc hl
240   jp computenewupdate
241
242.codeGotoX
243
244   ld b,(hl)
245   inc hl
246   jp computenewupdate
247
248.codeGotoY
249
250   ld c,(hl)
251   inc hl
252   jp computenewupdate
253
254.codePString
255   ld a,(hl)
256   inc hl
257   ld d,(hl)
258   inc hl
259   push hl
260   ld h,d
261   ld l,a
262   call psloop
263   pop hl
264   jp psloop
265
266.codeInvalidate
267   ld a,(hl)           ; parameter following INVALIDATE (0/1)
268   inc hl
269   srl e
270   rra
271   rl e
272   jp psloop
273
274.codeHome
275
276   ld bc,0
277   jp computenewupdate
278
279.codeReturn
280
281   ld b,0
282   inc c
283   jp computenewupdate
284
285.codeRepeat
286
287   ld a,(hl)           ; # times to repeat
288   inc hl
289.reploop
290   push hl             ; save string position at start of repeat block
291   push af             ; save # remaining iterations
292   call psloop         ; returns after endrepeat or 0 terminator
293   pop af
294   dec a               ; any more iterations?
295   jr z, nomoreiter
296   pop hl              ; restore string pointer for next repeat
297   jp reploop
298.nomoreiter
299   pop af              ; trash saved string position
300   jp psloop
301
302.codeEndRepeat
303
304   ret
305
306.codeTC                      ; a 16 bit tile code follows
307
308   ; first check if in bounds
309
310   ld a,b
311   cp (ix+2)
312   jr nc, codeRight2
313   ld a,c
314   cp (ix+3)
315   jr nc, codeRight2
316
317   ; are we invalidating?
318
319   bit 0,e
320   push hl
321   exx
322   jr z, noinvalidation2
323
324   ; invalidate the char
325
326   ld a,(de)
327   xor $80
328   jp p, noinvalidation2     ; if already invalidated, skip
329   ld (de),a
330   ld (hl),d
331   inc hl
332   ld (hl),e
333   ld hl,5
334   add hl,de
335
336.noinvalidation2
337
338   pop bc                    ; bc = & 16-bit tile
339   ld a,(bc)
340   inc de
341   ld (de),a                 ; write tile into sp1_update
342   inc bc
343   ld a,(bc)
344   inc de
345   ld (de),a
346   dec de
347   dec de
348
349   exx
350
351.codeRight2                  ; skip 16-bit tile code in string
352
353   inc hl
354   inc hl
355
356   ; advance to next char on right
357
358   jp codeRight
359
360.codeTransparent
361
362   ; are we invalidating?
363
364   bit 0,e
365   jp z, codeRight
366
367   ; invalidate the char
368
369   exx
370   ld a,(de)
371   xor $80
372   jp p, noinvalidation20    ; if already invalidated, skip
373   ld (de),a
374   ld (hl),d
375   inc hl
376   ld (hl),e
377   ld hl,5
378   add hl,de
379
380.noinvalidation20
381
382   exx
383   jp codeRight
384
385.printable                   ; a = tile#
386
387   ld (SP1V_TEMP_AF + 1),a
388
389   ; first check if in bounds
390
391   ld a,b
392   cp (ix+2)
393   jr nc, codeRight
394   ld a,c
395   cp (ix+3)
396   jr nc, codeRight
397
398   ; are we invalidating?
399
400   bit 0,e
401   exx
402   jr z, noinvalidation
403
404   ; invalidate the char
405
406   ld a,(de)
407   xor $80
408   jp p, noinvalidation      ; if already invalidated, skip
409   ld (de),a
410   ld (hl),d
411   inc hl
412   ld (hl),e
413   ld hl,5
414   add hl,de
415
416.noinvalidation
417
418   ex de,hl
419   inc hl
420   ld a,(SP1V_TEMP_AF + 1)
421   ld (hl),a                 ; store tile
422   inc hl
423   ld (hl),0
424
425   ; advance to next char on right
426
427   dec hl
428   dec hl
429   ex de,hl
430   exx
431
432.codeRight
433
434   inc b                     ; increase x coord
435   bit 1,e                   ; are we doing x wrap?
436   jr nz, yesxwrap
437
438.inxbounds
439
440   exx                       ; move update struct to right
441   ld a,9
442   add a,e
443   ld e,a
444   jp nc, noinc1
445   inc d
446.noinc1
447   exx
448
449   jp psloop
450
451.yesxwrap
452
453   ld a,b
454   cp (ix+2)
455   jr c, inxbounds
456   ld b,0
457
458   bit 2,e                   ; are we doing yinc?
459   jr z, noyinc
460   inc c
461
462   bit 3,e                   ; are we doing ywrap?
463   jr z, noyinc
464   ld a,c
465   cp (ix+3)
466   jr c, noyinc
467   ld c,0
468
469.noyinc
470.computenewupdate
471
472   ; need to compute struct sp1_update for new coords
473
474   push bc
475   exx
476   ex (sp),hl
477   ld a,(ix+0)
478   add a,l
479   ld d,a
480   ld a,(ix+1)
481   add a,h
482   ld e,a
483   call sp1_GetUpdateStruct_callee + ASMDISP_SP1_GETUPDATESTRUCT_CALLEE
484   ex de,hl
485   pop hl
486   exx
487
488   jp psloop
489
490.codeLeft
491
492   dec b
493   bit 1,e
494   jr nz, yesxwrap2
495
496.inxbounds2
497
498   exx
499   ld a,-9
500   add a,e
501   ld e,a
502   ld a,$ff
503   adc a,d
504   ld d,a
505   exx
506   jp psloop
507
508.yesxwrap2
509
510   ld a,b
511   cp (ix+2)
512   jr c, inxbounds2
513   ld b,(ix+2)
514   dec b
515
516   bit 2,e
517   jr z, computenewupdate
518   dec c
519
520   bit 3,e
521   jr z, computenewupdate
522
523   ld a,c
524   cp (ix+3)
525   jr c, computenewupdate
526   ld c,(ix+3)
527   dec c
528   jp computenewupdate
529
530.codeUp
531
532   dec c
533   bit 3,e
534   jr nz, yesywrap
535
536.inybounds
537
538   exx
539   ld a,+(-SP1V_DISPWIDTH*9) & 0xff
540   add a,e
541   ld e,a
542
543   ld a,-SP1V_DISPWIDTH*9/256
544;    ld a,+(((SP1V_DISPWIDTH*9):$ffff)+1)/256
545
546   adc a,d
547   ld d,a
548   exx
549   jp psloop
550
551.yesywrap
552
553   ld a,c
554   cp (ix+3)
555   jr c, inybounds
556   ld c,(ix+3)
557   dec c
558   jp computenewupdate
559
560.codeDown
561
562   inc c
563   bit 3,e
564   jr nz, yesywrap2
565
566.inybounds2
567
568   exx
569   ld a,0+(SP1V_DISPWIDTH*9)%256
570   add a,e
571   ld e,a
572   ld a,0+(SP1V_DISPWIDTH*9)/256
573   adc a,d
574   ld d,a
575   exx
576   jp psloop
577
578.yesywrap2
579
580   ld a,c
581   cp (ix+3)
582   jr c, inybounds2
583   ld c,0
584   jp computenewupdate
585