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