]> git.sur5r.net Git - cc65/blob - libsrc/atari/atari_tgi_common.inc
b4af0676342999f66635cbf1745e4540b33359d3
[cc65] / libsrc / atari / atari_tgi_common.inc
1 ;
2 ; Generic Atari graphics driver
3 ;
4
5 ; ******************************************************************************
6
7         ; ----------------------------------------------------------------------
8         ;
9         ; Header. Includes jump table and constants.
10         ;
11         ; ----------------------------------------------------------------------
12
13 .segment        "JUMPTABLE"
14
15 ; Header
16
17         .byte   $74, $67, $69           ; "tgi"
18         .byte   TGI_API_VERSION         ; TGI API version number
19         .word   x_res                   ; X resolution
20         .word   y_res                   ; Y resolution
21         .byte   colors                  ; Number of drawing colors
22         .byte   pages                   ; Number of screens available
23         .byte   8                       ; System font X size
24         .byte   8                       ; System font Y size
25         .word   aspect                  ; Aspect ratio
26
27 ; Function table
28
29         .addr   INSTALL
30         .addr   UNINSTALL
31         .addr   INIT
32         .addr   DONE
33         .addr   GETERROR
34         .addr   CONTROL
35         .addr   CLEAR
36         .addr   SETVIEWPAGE
37         .addr   SETDRAWPAGE
38         .addr   SETCOLOR
39         .addr   SETPALETTE
40         .addr   GETPALETTE
41         .addr   GETDEFPALETTE
42         .addr   SETPIXEL
43         .addr   GETPIXEL
44         .addr   LINE
45         .addr   BAR
46         .addr   TEXTSTYLE
47         .addr   OUTTEXT
48         .addr   0                       ; IRQ entry is unused
49
50 ; ******************************************************************************
51
52         ; ----------------------------------------------------------------------
53         ;
54         ; Parameters
55         ;
56         ; ----------------------------------------------------------------------
57
58         x1      := ptr1
59         y1      := ptr2
60         x2      := ptr3
61         y2      := ptr4
62         radius  := tmp1
63
64 ; ******************************************************************************
65
66         ; ----------------------------------------------------------------------
67         ;
68         ; Global variables
69         ;
70         ; ----------------------------------------------------------------------
71
72         sptr    := regsave + 2
73
74 .bss
75         error:
76                 .res    1       ; Error code
77         .if grmode = 9 || grmode = 11
78         palette = default_palette
79         .else
80         palette:
81                 .res    colors  ; The current palette
82         .endif
83         mask:
84                 .res    1       ; Current pixel mask
85         griocb:
86                 .res    1       ; IOCB channel number for graphics
87
88 .if pages = 2
89         p0scr:
90                 .res    1       ; High byte of screen address for screen page 0
91         p0dls:
92                 .res    1       ; High byte of display list address for screen page 0
93                                 ; Page 1's addresses are 8K higher
94 .endif
95
96 .data
97         mag_x:
98                 .byte   1       ; Horizontal text scaling factor
99         mag_y:
100                 .byte   1       ; Vertical text scaling factor
101         mag_x8:
102                 .word   8       ; Horizontal text scaling factor * 8
103         mag_y8:
104                 .word   8       ; Vertical text scaling factor * 8
105         text_dir:
106                 .byte   0       ; Text direction,
107
108 .code
109
110 ; ******************************************************************************
111
112 .macro  put_pixel
113
114         ; ----------------------------------------------------------------------
115         ;
116         ; Put a pixel at (sptr),y using x as the bit mask offset
117         ;
118         ; ----------------------------------------------------------------------
119
120         lda     (sptr),y
121         eor     mask
122         and     mask_table,x
123         eor     (sptr),y
124         sta     (sptr),y
125 .endmacro
126
127 ; ******************************************************************************
128
129 .rodata
130 screen_device:
131         .byte "S:",$9B          ; Device code for screen
132 screen_device_length := * - screen_device
133
134 .code
135
136 .proc INIT
137
138         ; ----------------------------------------------------------------------
139         ;
140         ; INIT: Switch to graphics mode
141         ;
142         ; ----------------------------------------------------------------------
143
144
145 .code
146         ; Initialize drawing color
147         ldx     #$FF
148         stx     mask
149
150         ; Find a free IOCB
151         clc
152         lda     #$70
153 search: tax
154         ldy     ICHID,x
155         cpy     #$FF
156         beq     found
157         sbc     #$10
158         bcs     search
159
160         ; No free IOCB
161         lda     #TGI_ERR_NO_IOCB
162         sta     error
163         rts
164
165 found:  ; Check if enough RAM is available
166         lda     #0
167         sub     #<mem_needed
168         tay
169         lda     RAMTOP
170         sbc     #>mem_needed
171         cmp     APPMHI + 1
172         bcc     nomem
173         bne     switch
174         cpy     APPMHI
175         bcs     switch
176
177         ; No memory
178 nomem:  lda     #TGI_ERR_NO_MEM
179         sta     error
180         rts
181
182         ; Switch into graphics mode
183 switch: lda     #OPEN
184         sta     ICCOM,x
185         lda     #OPNIN | OPNOT
186         sta     ICAX1,x
187         lda     #grmode
188         sta     ICAX2,x
189         lda     #<screen_device
190         sta     ICBAL,x
191         lda     #>screen_device
192         sta     ICBAH,x
193         lda     #<screen_device_length
194         sta     ICBLL,x
195         lda     #>screen_device_length
196         sta     ICBLH,x
197         jsr     CIOV
198
199         .if pages = 2
200         ; Reserve 8K of high memory
201         lda     RAMTOP
202         sub     #32
203         sta     RAMTOP
204         ; Close and reopen graphics
205         lda     #CLOSE
206         sta     ICCOM,x
207         jsr     CIOV
208         ; Reopen graphics
209         lda     #OPEN
210         sta     ICCOM,x
211         lda     #OPNIN | OPNOT
212         sta     ICAX1,x
213         lda     #grmode
214         sta     ICAX2,x
215         lda     #<screen_device
216         sta     ICBAL,x
217         lda     #>screen_device
218         sta     ICBAH,x
219         lda     #<screen_device_length
220         sta     ICBLL,x
221         lda     #>screen_device_length
222         sta     ICBLH,x
223         jsr     CIOV
224         ; Save screen poniters
225         lda     SAVMSC + 1
226         sta     p0scr
227         lda     SDLSTH
228         sta     p0dls
229         .endif
230
231         stx     griocb
232         ; Reset the error code and return
233         lda     #TGI_ERR_OK
234         sta     error
235         rts
236 .endproc
237
238 ; ******************************************************************************
239
240 .proc DONE
241
242         ; ----------------------------------------------------------------------
243         ;
244         ; DONE: Switch back to text mode
245         ;
246         ; ----------------------------------------------------------------------
247
248 .code
249         .if pages = 2
250         ; Free 8K of high memory
251         lda     RAMTOP
252         add     #32
253         sta     RAMTOP
254         .endif
255
256         ; Clear griocb
257         lda     #$FF
258         ldx     griocb
259         sta     griocb
260
261         ; Close the S: device
262         lda     #CLOSE
263         sta     ICCOM,x
264         jsr     CIOV
265
266         ; Reopen it in Graphics 0
267         lda     #OPEN
268         sta     ICCOM,x
269         lda     #OPNIN | OPNOT
270         sta     ICAX1,x
271         lda     #0
272         sta     ICAX2,x
273         lda     #<screen_device
274         sta     ICBAL,x
275         lda     #>screen_device
276         sta     ICBAH,x
277         lda     #<screen_device_length
278         sta     ICBLL,x
279         lda     #>screen_device_length
280         sta     ICBLH,x
281         jsr     CIOV
282
283         ; Now close it again; we don't need it anymore
284         lda     #CLOSE
285         sta     ICCOM,x
286         jmp     CIOV
287 .endproc
288
289 ; ******************************************************************************
290
291 .proc GETERROR
292
293         ; ----------------------------------------------------------------------
294         ;
295         ; GETERROR: Return the error code in A and clear it
296         ;
297         ; ----------------------------------------------------------------------
298
299 .code
300         ldx     #TGI_ERR_OK
301         lda     error
302         stx     error
303         rts
304 .endproc
305
306 ; ******************************************************************************
307
308 .proc CLEAR
309
310         ; ----------------------------------------------------------------------
311         ;
312         ; CLEAR: Clear the screen
313         ;
314         ; ----------------------------------------------------------------------
315
316 .code
317         ; Load the screen address in sptr
318         lda     SAVMSC
319         sta     sptr
320         lda     SAVMSC + 1
321         sta     sptr + 1
322
323         ; Fill with zero
324         lda     #0
325         tay
326
327         ; Clear full pages if any
328         .if >(scrsize) > 0
329         ldx     #>(scrsize)
330 loop1:  sta     (sptr),y
331         iny
332         bne     loop1
333         inc     sptr + 1
334         dex
335         bne     loop1
336         .endif
337
338         ; Clear the rest, if any
339         .if <(scrsize) > 0
340 loop2:  sta     (sptr),y
341         iny
342         cpy     #<(scrsize)
343         bne     loop2
344         .endif
345
346         rts
347 .endproc
348
349 ; ******************************************************************************
350
351 .proc GETPALETTE
352
353         ; ----------------------------------------------------------------------
354         ;
355         ; GETPALETTE: Return the current palette in A/X
356         ;
357         ; ----------------------------------------------------------------------
358
359 .code
360         lda     #<palette
361         ldx     #>palette
362         rts
363 .endproc
364
365 ; ******************************************************************************
366
367 .proc GETDEFPALETTE
368
369         ; ----------------------------------------------------------------------
370         ;
371         ; GETDEFPALETTE: Return the default palette in A/X
372         ;
373         ; ----------------------------------------------------------------------
374
375 .code
376         lda     #<default_palette
377         ldx     #>default_palette
378         rts
379 .endproc
380
381 ; ******************************************************************************
382
383 .proc SETCOLOR
384
385         ; ----------------------------------------------------------------------
386         ;
387         ; SETCOLOR: Set the drawing color (in A)
388         ;
389         ; ----------------------------------------------------------------------
390
391 .code
392         tax
393         .if grmode = 9
394         ; Map colors like this: 0 -> 0, 1 -> 15, 2 -> 1, 3 -> 2 etc.
395         beq     @cont
396         cpx     #1
397         bne     @map
398         ldx     #16
399 @map:   dex
400 @cont:  .endif
401         lda     masks,x
402         sta     mask
403         rts
404 .endproc
405
406 ; ******************************************************************************
407
408 .proc CALC
409
410         ; ----------------------------------------------------------------------
411         ;
412         ; CALC: Calculate the screen address
413         ;       in
414         ;               x1 (ptr1)       x coordinate
415         ;               y1 (ptr2)       y coordinate
416         ;       out
417         ;               sptr + y        screen address
418         ;               x               bit mask index
419         ;
420         ; ----------------------------------------------------------------------
421
422 .bss
423         temp:   .res    1
424 .code
425         ; calculate line offset
426         lda     y1 + 1
427         sta     temp
428         lda     y1
429
430         .if x_res / ppb = 40
431         .define yrep 3
432         .elseif x_res / ppb = 20
433         .define yrep 2
434         .elseif x_res / ppb = 10
435         .define yrep 1
436         .endif
437
438         .repeat yrep
439           asl   a
440           rol   temp
441         .endrepeat
442         sta     sptr
443         ldx     temp
444         stx     sptr + 1
445         .repeat 2
446           asl   a
447           rol   temp
448         .endrepeat
449         add     sptr
450         sta     sptr
451         lda     temp
452         adc     sptr + 1
453         sta     sptr + 1
454
455         ; calculate bit mask offset
456         lda     x1
457         and     #ppb - 1
458         tax
459
460         ; calculate row offset
461         lda     x1 + 1
462         sta     temp
463         lda     x1
464
465         .if ppb = 8
466         .define xrep 3
467         .elseif ppb = 4
468         .define xrep 2
469         .elseif ppb = 2
470         .define xrep 1
471         .endif
472         .repeat xrep
473         lsr     temp
474         ror     a
475         .endrepeat
476         tay
477
478         ; sptr += SAVMSC
479         lda     SAVMSC
480         add     sptr
481         sta     sptr
482         lda     SAVMSC + 1
483         adc     sptr + 1
484         sta     sptr + 1
485
486         ; We're done!
487         rts
488 .endproc
489
490 ; ******************************************************************************
491
492 .proc SETPIXEL
493
494         ; ----------------------------------------------------------------------
495         ;
496         ; Draw one pixel at x1, y1
497         ;
498         ; ----------------------------------------------------------------------
499
500 .code
501         jsr     CALC
502         put_pixel
503         rts
504 .endproc
505
506 ; ******************************************************************************
507
508 .proc GETPIXEL
509
510         ; ----------------------------------------------------------------------
511         ;
512         ; GETPIXEL: Read the color value of a pixel and return it in A/X
513         ;
514         ; ----------------------------------------------------------------------
515
516 .code
517         jsr     CALC
518         lda     (sptr),y
519         and     mask_table,x
520         .if ppb = 8
521         beq     zero
522         lda     #1
523 zero:   ldx     #0
524         rts
525         .elseif ppb = 4
526 loop:   cpx     #3
527         beq     cont
528         lsr     a
529         lsr     a
530         inx
531         bne     loop
532 cont:   and     #$03
533         rts
534         .elseif ppb = 2
535         dex
536         bne     shift
537         and     #$0F
538         jmp     exit
539 shift:  ldx     #0
540         lsr     a
541         lsr     a
542         lsr     a
543         lsr     a
544
545         ; Mode 9 mapping
546 exit:   .if grmode = 9
547         ; Map colors like this: 0 -> 0, 15 -> 1, 2 -> 3, 3 -> 4 etc.
548         beq     @cont
549         cmp     #15
550         bne     @map
551         lda     #0
552 @map:   add     #1
553 @cont:  .endif
554
555         ; Mode 10 mapping
556         .if grmode = 10
557         ; Map out of range colors like this:
558         ;  9 -> 8
559         ; 10 -> 8
560         ; 11 -> 8
561         ; 12 -> 0
562         ; 13 -> 1
563         ; 14 -> 2
564         ; 15 -> 3
565         cmp     #8
566         bcs     @cont
567         sub     #12
568         bcs     @cont
569         lda     #8
570 @cont:  .endif
571
572         ; Done!
573         rts
574         .endif
575 .endproc
576
577 ; ******************************************************************************
578
579 .proc LINE
580
581         ; ----------------------------------------------------------------------
582         ;
583         ; LINE: Draw a line from x1,y1 to x2,y2
584         ;
585         ; ----------------------------------------------------------------------
586
587 ; locals
588
589         dx      :=      sreg
590         dy      :=      y1
591         dx2     :=      x2
592         dy2     :=      y2
593         iy      :=      tmp1
594         err     :=      tmp3
595
596 .code
597         ; dx = x2 - x1
598         lda     x2
599         sub     x1
600         sta     dx
601         lda     x2 + 1
602         sbc     x1 + 1
603         sta     dx + 1
604         ; if dx is positive, no problem
605         bcs     dx_positive
606
607         ; if dx is negative, swap x1,y1 with x2,y2
608         lda     x1      ; x1 <-> x2, low byte
609         ldx     x2
610         sta     x2
611         stx     x1
612         lda     x1 + 1  ; x1 <-> x2, high byte
613         ldx     x2 + 1
614         sta     x2 + 1
615         stx     x1 + 1
616         lda     y1      ; y1 <-> y2, low byte
617         ldx     y2
618         sta     y2
619         stx     y1
620         lda     y1 + 1  ; y1 <-> y2, high byte
621         ldx     y2 + 1
622         sta     y2 + 1
623         stx     y1 + 1
624         ; Calculate again
625         jmp     LINE
626
627 dx_positive:
628         ; Calculate coords
629         jsr     CALC
630
631         ; dy = y2 - y1
632         lda     y2
633         sub     y1
634         sta     dy
635         lda     y2 + 1
636         sbc     y1 + 1
637         sta     dy + 1
638
639         ; if dy is negative
640         bcs     dy_positive
641         ; dy = -dy
642         lda     #0
643         sub     dy
644         sta     dy
645         lda     #0
646         sbc     dy + 1
647         sta     dy + 1
648         ; iy = -row_size
649         lda     #<(65536 - x_res / ppb)
650         sta     iy
651         lda     #>(65536 - x_res / ppb)
652         sta     iy + 1
653         bne     skip_iy_1               ; always
654
655 dy_positive:
656         ; iy = row_size
657         lda     #<(x_res / ppb)
658         sta     iy
659         lda     #>(x_res / ppb)
660         sta     iy + 1
661 skip_iy_1:
662
663         ; dx2 = dx * 2
664         lda     dx
665         asl     a
666         sta     dx2
667         lda     dx + 1
668         rol     a
669         sta     dx2 + 1
670
671         ; dy2 = dy * 2
672         lda     dy
673         asl     a
674         sta     dy2
675         lda     dy + 1
676         rol     a
677         sta     dy2 + 1
678
679         ; if dx >= dy
680         lda     dx
681         cmp     dy
682         lda     dx + 1
683         sbc     dy + 1
684         bcc     dy_major
685
686         ; dx is the major axis
687
688         ; err = dy2 - dx
689         lda     dy2
690         sub     dx
691         sta     err
692         lda     dy2 + 1
693         sbc     dx + 1
694         sta     err + 1
695
696         .scope
697 loop:   ; main loop
698         put_pixel
699         ; if err >= 0
700         lda     err + 1
701         bmi     err_neg
702         ; err -= dx2
703         lda     err
704         sub     dx2
705         sta     err
706         lda     err + 1
707         sbc     dx2 + 1
708         sta     err + 1
709         ; move_vertical (iy)
710         lda     sptr
711         add     iy
712         sta     sptr
713         lda     sptr + 1
714         adc     iy + 1
715         sta     sptr + 1
716 err_neg:
717         ; err += dy2
718         lda     err
719         add     dy2
720         sta     err
721         lda     err + 1
722         adc     dy2 + 1
723         sta     err + 1
724         ; move_right
725         inx
726         cpx     #ppb
727         bne     end_move
728         ldx     #0
729         iny
730         bne     end_move
731         inc     sptr + 1
732 end_move:
733         ; loop while dx-- >= 0
734         lda     dx
735         ora     dx + 1
736         beq     exit
737         dec     dx
738         lda     dx
739         cmp     #$FF
740         bne     loop
741         dec     dx + 1
742         jmp     loop
743 exit:   rts
744         .endscope
745
746 dy_major:
747         ; dy is the major axis
748
749         ; err = dx2 - dy;
750         lda     dx2
751         sub     dy
752         sta     err
753         lda     dx2 + 1
754         sbc     dy + 1
755         sta     err + 1
756
757         .scope
758 loop:   ; main loop
759         put_pixel
760         ; if err >= 0
761         lda     err + 1
762         bmi     end_move
763         ; err -= dy2
764         lda     err
765         sub     dy2
766         sta     err
767         lda     err + 1
768         sbc     dy2 + 1
769         sta     err + 1
770         ; move_right
771         inx
772         cpx     #ppb
773         bne     end_move
774         ldx     #0
775         iny
776         bne     end_move
777         inc     sptr + 1
778 end_move:
779         ; err += dx2
780         lda     err
781         add     dx2
782         sta     err
783         lda     err + 1
784         adc     dx2 + 1
785         sta     err + 1
786         ; move_vertical(iy)
787         lda     sptr
788         add     iy
789         sta     sptr
790         lda     sptr + 1
791         adc     iy + 1
792         sta     sptr + 1
793         ; loop while dy-- >= 0
794         lda     dy
795         ora     dy + 1
796         beq     exit
797         dec     dy
798         lda     dy
799         cmp     #$FF
800         bne     loop
801         dec     dy + 1
802         jmp     loop
803 exit:   rts
804         .endscope
805 .endproc
806
807 ; ******************************************************************************
808
809 .proc clipped_bar
810
811         ; ----------------------------------------------------------------------
812         ;
813         ; Clip and draw bar
814         ;
815         ; ----------------------------------------------------------------------
816
817 .code
818         lda     y1 + 1
819         bne     off
820         lda     y1
821         cmp     #y_res
822         bcs     off
823
824         lda     x1 + 1
825         .if >(x_res - 1) > 0
826         cmp     #>x_res
827         bcc     check2
828         .endif
829         bne     off
830         lda     x1
831         cmp     #<x_res
832         bcc     check2
833 off:    rts
834
835 check2: lda     y2 + 1
836         bne     off
837         lda     y2
838         cmp     #y_res
839         bcs     off
840
841         lda     x2 + 1
842         .if >(x_res - 1) > 0
843         cmp     #>x_res
844         bcc     BAR
845         .endif
846         bne     off
847         lda     x2
848         cmp     #<x_res
849         bcs     off
850 .endproc
851
852 ; ******************************************************************************
853
854 .proc BAR
855
856         ; ----------------------------------------------------------------------
857         ;
858         ; BAR: Draw a filled rectangle with the corners at x1,y1,x2,y2
859         ;
860         ; ----------------------------------------------------------------------
861
862 ; locals
863         lmem    := sreg
864 .bss
865         lmask:  .res 1
866         rmask:  .res 1
867         dy:     .res 1
868         dx:     .res 1
869         fmask:  .res 1
870 .code
871         ; dy = y2 - y1 + 1
872         lda     y2
873         sub     y1
874         sta     dy
875         inc     dy
876         ; Calculate upper left corner
877         jsr     CALC
878         ; Save the values
879         tya
880         add     sptr
881         sta     lmem
882         lda     sptr + 1
883         adc     #0
884         sta     lmem + 1
885         lda     bar_table,x
886         sta     lmask
887         ; Calculate upper right corner
888         lda     x2
889         sta     x1
890         .if >(x_res - 1) > 0
891         lda     x2 + 1
892         sta     x1 + 1
893         .endif
894         jsr     CALC
895         ; Save the values
896         tya
897         add     sptr
898         sta     sptr
899         bcc     skips
900         inc     sptr + 1
901 skips:  inx
902         lda     bar_table,x
903         eor     #$FF
904         sta     rmask
905         ; Calculate memory difference between x1 and x2
906         lda     sptr
907         sub     lmem
908         sta     dx
909 loop:   ; Main loop
910         ldy     #0
911         ldx     dx
912         beq     same
913         ; Left
914         lda     (lmem),y
915         eor     mask
916         and     lmask
917         eor     (lmem),y
918         sta     (lmem),y
919         iny
920         ; Between
921         lda     mask
922         jmp     next
923 btwn:   sta     (lmem),y
924         iny
925 next:   dex
926         bne     btwn
927         ; Right
928         lda     (lmem),y
929         eor     mask
930         and     rmask
931         eor     (lmem),y
932         sta     (lmem),y
933         jmp     cont
934 same:   ; Same byte
935         lda     lmask
936         and     rmask
937         sta     fmask
938         lda     (lmem),y
939         eor     mask
940         and     fmask
941         eor     (lmem),y
942         sta     (lmem),y
943 cont:   ; Go to next row
944         lda     lmem
945         add     #<(x_res / ppb)
946         sta     lmem
947         bcc     skipm
948         inc     lmem + 1
949 skipm:  ; Loop while --dy > 0
950         dec     dy
951         bne     loop
952
953         rts
954
955 .endproc
956
957 ; ******************************************************************************
958
959 .proc TEXTSTYLE
960
961         ; ----------------------------------------------------------------------
962         ;
963         ; TEXTSTYLE: Set text style. Scale factors in X and Y and direction in A
964         ;
965         ; ----------------------------------------------------------------------
966
967 .code
968         stx     mag_x
969         sty     mag_y
970         ; Save text direction in bit 8 so that we can use BIT instruction later
971         lsr     a
972         ror     a
973         sta     text_dir
974         ; Save 8 * scaling factors
975         lda     #0
976         sta     mag_x8 + 1
977         sta     mag_y8 + 1
978         ; Save 8 * mag_x
979         txa
980         .repeat 3
981         asl     a
982         rol     mag_x8 + 1
983         .endrepeat
984         sta     mag_x8
985         ; Save 8 * mag_y
986         tya
987         .repeat 3
988         asl     a
989         rol     mag_y8 + 1
990         .endrepeat
991         sta     mag_y8
992         ; Done!
993         rts
994 .endproc
995
996 ; ******************************************************************************
997
998 .proc OUTTEXT
999
1000         ; ----------------------------------------------------------------------
1001         ;
1002         ; OUTTEXT: Draw text at x1, y1. String is in ptr3
1003         ;
1004         ; ----------------------------------------------------------------------
1005
1006 ; locals
1007         string  := tmp1
1008         cols    := tmp3
1009         pixels  := tmp4
1010         font    := regsave
1011 .rodata
1012         ataint: .byte   64,0,32,96
1013 .bss
1014         rows:   .res    1
1015         .if >(x_res - 1) > 0
1016         oldx1:  .res    2
1017         oldx2:  .res    2
1018         .else
1019         oldx1:  .res    1
1020         oldx2:  .res    1
1021         .endif
1022         oldy1:  .res    1
1023         oldy2:  .res    1
1024         inv:    .res    1
1025 .code
1026         ; Don't draw zero sized characters
1027         lda     mag_x
1028         beq     @exit
1029         lda     mag_y
1030         bne     @cont
1031 @exit:  rts
1032 @cont:  ; Save string address, ptr3 is needed by BAR
1033         lda     ptr3
1034         sta     string
1035         lda     ptr3 + 1
1036         sta     string + 1
1037
1038         bit     text_dir
1039         bmi     vert
1040
1041         ; Calculate x2
1042         lda     mag_x
1043         sub     #1
1044         add     x1
1045         sta     x2
1046         .if >(x_res - 1) > 0
1047         lda     x1 + 1
1048         adc     #0
1049         sta     x2 + 1
1050         .else
1051         lda     #0
1052         sta     x2 + 1
1053         .endif
1054
1055         ; Calculate y2 and adjust y1
1056         dec     y1
1057         lda     y1
1058         sta     y2
1059         sub     mag_y
1060         add     #1
1061         sta     y1
1062         lda     #0
1063         sta     y2 + 1
1064
1065         jmp     while
1066
1067         ; Calculate for vertical text
1068 vert:   lda     x1
1069         sub     #1
1070         sta     x2
1071         lda     x1 + 1
1072         sbc     #0
1073         sta     x2 + 1
1074         lda     x1
1075         sub     mag_y
1076         sta     x1
1077         lda     x1 + 1
1078         sbc     #0
1079         sta     x1 + 1
1080
1081         lda     mag_x
1082         sub     #1
1083         add     y1
1084         sta     y2
1085         lda     #0
1086         sta     y2 + 1
1087         beq     while           ; Always
1088
1089         ; Main loop
1090 loop:   inc     string
1091         bne     skiph
1092         inc     string + 1
1093 skiph:  ; Save coords
1094         jsr     save_text_y
1095         ; Draw one character
1096         jsr     outchar
1097         ; Restore coords
1098         jsr     restore_text_y
1099         ; End of loop
1100 while:  ldy     #0
1101         lda     (string),y
1102         bne     loop            ; Check for null character
1103         rts
1104
1105         ; --------------------
1106         ; Output one character
1107 outchar:
1108         ; Convert to ANTIC code
1109         tay
1110         rol     a
1111         rol     a
1112         rol     a
1113         rol     a
1114         and     #3
1115         tax
1116         tya
1117         and     #$9f
1118         ora     ataint,x
1119         ; Save and clear inverse video bit
1120         sta     inv
1121         and     #$7F
1122         ; Calculate font data address
1123         sta     font
1124         lda     #0
1125         sta     font + 1
1126         .repeat 3
1127         asl     font
1128         rol     a
1129         .endrepeat
1130         adc     CHBAS
1131         sta     font + 1
1132         ; Save old coords
1133         bit     text_dir
1134         bpl     @hor
1135         lda     y1
1136         sta     oldy1
1137         lda     y2
1138         sta     oldy2
1139         jmp     @cont
1140 @hor:   lda     x1
1141         sta     oldx1
1142         lda     x2
1143         sta     oldx2
1144         .if >(x_res - 1) > 0
1145         lda     x1 + 1
1146         sta     oldx1 + 1
1147         lda     x2 + 1
1148         sta     oldx2 + 1
1149         .endif
1150         ; Get glyph pixels
1151 @cont:  ldy     #7
1152         ; Put one row of the glyph
1153 putrow: sty     rows
1154         lda     (font),y
1155         bit     inv
1156         bpl     noinv
1157         eor     #$FF
1158 noinv:  sta     pixels
1159         lda     #7
1160         sta     cols
1161         ; Put one column of the row
1162 putcol: asl     pixels
1163         bcc     next_col
1164         lda     x1
1165         pha
1166         lda     x1 + 1
1167         pha
1168         jsr     clipped_bar
1169         pla
1170         sta     x1 + 1
1171         pla
1172         sta     x1
1173 next_col:
1174         ; Go to next column
1175         jsr     inc_x
1176         dec     cols
1177         bpl     putcol
1178 next_row:
1179         ; Go to next row
1180         jsr     dec_y
1181         ; Restore old values
1182         bit     text_dir
1183         bpl     @hor
1184         lda     oldy1
1185         sta     y1
1186         lda     oldy2
1187         sta     y2
1188         jmp     @cont
1189 @hor:   lda     oldx1
1190         sta     x1
1191         lda     oldx2
1192         sta     x2
1193         .if >(x_res - 1) > 0
1194         lda     oldx1 + 1
1195         sta     x1 + 1
1196         lda     oldx2 + 1
1197         sta     x2 + 1
1198         .endif
1199         ; Next row
1200 @cont:  ldy     rows
1201         dey
1202         bpl     putrow
1203
1204         ; We're done!
1205         rts
1206
1207
1208 ; -------------------------
1209 inc_x:  ; increase x coords
1210         bit     text_dir
1211         bmi     @vert
1212
1213         lda     mag_x
1214         add     x1
1215         sta     x1
1216         bcc     @1
1217         inc     x1 + 1
1218 @1:     lda     mag_x
1219         add     x2
1220         sta     x2
1221         bcc     @2
1222         inc     x2 + 1
1223 @2:     rts
1224
1225 @vert:  lda     y1
1226         sub     mag_x
1227         sta     y1
1228         lda     y2
1229         sub     mag_x
1230         sta     y2
1231         rts
1232
1233 ; -------------------------
1234 dec_y:  ; decrease y coords
1235         bit     text_dir
1236         bmi     @vert
1237
1238         lda     y1
1239         sub     mag_y
1240         sta     y1
1241         bcs     @1
1242         dec     y1 + 1
1243 @1:     lda     y2
1244         sub     mag_y
1245         sta     y2
1246         bcs     @2
1247         dec     y2 + 1
1248 @2:     rts
1249
1250 @vert:  lda     x1
1251         sub     mag_y
1252         sta     x1
1253         bcs     @3
1254         dec     x1 + 1
1255 @3:     lda     x2
1256         sub     mag_y
1257         sta     x2
1258         bcs     @4
1259         dec     x2 + 1
1260 @4:     rts
1261
1262 ; -------------------------
1263 save_text_y: ; Save text's height coords
1264         bit     text_dir
1265         bmi     @vert
1266         ldx     y1
1267         stx     oldy1
1268         ldx     y2
1269         stx     oldy2
1270         rts
1271 @vert:  ldx     x1
1272         stx     oldx1
1273         ldx     x2
1274         stx     oldx2
1275         .if >(x_res - 1) > 0
1276         ldx     x1 + 1
1277         stx     oldx1 + 1
1278         ldx     x2 + 1
1279         stx     oldx2 + 1
1280         .endif
1281         rts
1282
1283 ; -------------------------
1284 restore_text_y: ; Position to next char
1285         bit     text_dir
1286         bmi     @vert
1287
1288         ldx     oldy1
1289         stx     y1
1290         ldx     oldy2
1291         stx     y2
1292         ldx     #0
1293         stx     y1 + 1
1294         stx     y2 + 1
1295
1296         lda     mag_x8
1297         add     x1
1298         sta     x1
1299         lda     mag_x8 + 1
1300         adc     x1 + 1
1301         sta     x1 + 1
1302         lda     mag_x8
1303         add     x2
1304         sta     x2
1305         lda     mag_x8 + 1
1306         adc     x2 + 1
1307         sta     x2 + 1
1308
1309         rts
1310
1311 @vert:  ldx     oldx1
1312         stx     x1
1313         ldx     oldx2
1314         stx     x2
1315         .if >(x_res - 1) > 0
1316         ldx     oldx1 + 1
1317         stx     x1 + 1
1318         ldx     oldx2 + 1
1319         stx     x2 + 1
1320         .endif
1321
1322         lda     y1
1323         sub     mag_x8
1324         sta     y1
1325         lda     y1 +1
1326         sbc     mag_x8 + 1
1327         sta     y1 + 1
1328         lda     y2
1329         sub     mag_x8
1330         sta     y2
1331         lda     y2 +1
1332         sbc     mag_x8 + 1
1333         sta     y2 + 1
1334
1335         rts
1336
1337 .endproc
1338
1339 .if pages = 2
1340 ; ******************************************************************************
1341
1342 .proc SETVIEWPAGE
1343
1344         ; ----------------------------------------------------------------------
1345         ;
1346         ; SETVIEWPAGE, page in A
1347         ;
1348         ; ----------------------------------------------------------------------
1349
1350 .code
1351         tax
1352         beq     cont
1353         lda     #32
1354
1355 cont:   add     p0dls
1356         cmp     SDLSTH
1357         beq     done            ; We're already in the desired page
1358
1359         ldx     RTCLOK + 2
1360         sta     SDLSTH
1361
1362         ; Wait until next VBLANK
1363 wait:   cpx     RTCLOK + 2
1364         beq     wait
1365
1366         ; Done
1367 done:   rts
1368 .endproc
1369
1370 ; ******************************************************************************
1371
1372 .proc SETDRAWPAGE
1373
1374         ; ----------------------------------------------------------------------
1375         ;
1376         ; SETDRAWPAGE, page in A
1377         ;
1378         ; ----------------------------------------------------------------------
1379
1380 .code
1381         tax
1382         beq     @cont
1383         lda     #32
1384 @cont:  add     p0scr
1385         sta     SAVMSC + 1
1386         rts
1387 .endproc
1388 .endif
1389
1390 ; ******************************************************************************
1391
1392         ; ----------------------------------------------------------------------
1393         ;
1394         ; Unimplemented functions that require an error code
1395         ;
1396         ; ----------------------------------------------------------------------
1397
1398 CONTROL:
1399         lda     #TGI_ERR_INV_FUNC
1400         sta     error
1401         ; fall through
1402
1403 ; ******************************************************************************
1404
1405         ; ----------------------------------------------------------------------
1406         ;
1407         ; Unimplemented functions that don't require an error code
1408         ;
1409         ; ----------------------------------------------------------------------
1410
1411 INSTALL:
1412 UNINSTALL:
1413 .if pages = 1
1414 SETVIEWPAGE:
1415 SETDRAWPAGE:
1416 .endif
1417         rts