]> git.sur5r.net Git - cc65/blob - libsrc/c64/tgi/c64-hi.s
Added library reference address to lightpen driver header.
[cc65] / libsrc / c64 / tgi / c64-hi.s
1 ;
2 ; Graphics driver for the 320x200x2 mode on the C64.
3 ;
4 ; Based on Stephen L. Judds GRLIB code
5 ;
6
7         .include        "zeropage.inc"
8
9         .include        "tgi-kernel.inc"
10         .include        "tgi-error.inc"
11
12
13         .macpack        generic
14
15
16 ; ------------------------------------------------------------------------
17 ; Header. Includes jump table and constants.
18
19 .segment        "JUMPTABLE"
20
21 ; First part of the header is a structure that has a magic and defines the
22 ; capabilities of the driver
23
24         .byte   $74, $67, $69           ; "tgi"
25         .byte   TGI_API_VERSION         ; TGI API version number
26         .addr   $0000                   ; Library reference
27         .word   320                     ; X resolution
28         .word   200                     ; Y resolution
29         .byte   2                       ; Number of drawing colors
30         .byte   1                       ; Number of screens available
31         .byte   8                       ; System font X size
32         .byte   8                       ; System font Y size
33         .word   $00D4                   ; Aspect ratio (based on 4/3 display)
34         .byte   0                       ; TGI driver flags
35
36 ; Next comes the jump table. With the exception of IRQ, all entries must be
37 ; valid and may point to an RTS for test versions (function not implemented).
38
39         .addr   INSTALL
40         .addr   UNINSTALL
41         .addr   INIT
42         .addr   DONE
43         .addr   GETERROR
44         .addr   CONTROL
45         .addr   CLEAR
46         .addr   SETVIEWPAGE
47         .addr   SETDRAWPAGE
48         .addr   SETCOLOR
49         .addr   SETPALETTE
50         .addr   GETPALETTE
51         .addr   GETDEFPALETTE
52         .addr   SETPIXEL
53         .addr   GETPIXEL
54         .addr   LINE
55         .addr   BAR
56         .addr   TEXTSTYLE
57         .addr   OUTTEXT
58         .addr   0                       ; IRQ entry is unused
59
60 ; ------------------------------------------------------------------------
61 ; Data.
62
63 ; Variables mapped to the zero page segment variables. Some of these are
64 ; used for passing parameters to the driver.
65
66 X1              := ptr1
67 Y1              := ptr2
68 X2              := ptr3
69 Y2              := ptr4
70 TEXT            := ptr3
71
72 ROW             := tmp2         ; Bitmap row...
73 COL             := tmp3         ; ...and column, both set by PLOT
74 TEMP            := tmp4
75 TEMP2           := sreg
76 POINT           := regsave
77 INRANGE         := regsave+2    ; PLOT variable, $00 = coordinates in range
78
79 CHUNK           := X2           ; Used in the line routine
80 OLDCHUNK        := X2+1         ; Dito
81
82 ; Absolute variables used in the code
83
84 .bss
85
86 ERROR:          .res    1       ; Error code
87 PALETTE:        .res    2       ; The current palette
88
89 BITMASK:        .res    1       ; $00 = clear, $FF = set pixels
90
91 ; INIT/DONE
92 OLDD018:        .res    1       ; Old register value
93
94 ; Line routine stuff
95 DX:             .res    2
96 DY:             .res    2
97
98 ; BAR variables
99 X1SAVE:         .res    2
100 Y1SAVE:         .res    2
101 X2SAVE:         .res    2
102 Y2SAVE:         .res    2
103
104 ; Text output stuff
105 TEXTMAGX:       .res    1
106 TEXTMAGY:       .res    1
107 TEXTDIR:        .res    1
108
109 ; Constants and tables
110
111 .rodata
112
113 DEFPALETTE:     .byte   $00, $01        ; White on black
114 PALETTESIZE     = * - DEFPALETTE
115
116 BITTAB:         .byte   $80,$40,$20,$10,$08,$04,$02,$01
117 BITCHUNK:       .byte   $FF,$7F,$3F,$1F,$0F,$07,$03,$01
118
119 CHARROM         := $D000                ; Character rom base address
120 CBASE           := $D000                ; Color memory base address
121 VBASE           := $E000                ; Video memory base address
122
123
124 .code
125
126 ; ------------------------------------------------------------------------
127 ; INSTALL routine. Is called after the driver is loaded into memory. May
128 ; initialize anything that has to be done just once. Is probably empty
129 ; most of the time.
130 ;
131 ; Must set an error code: NO
132 ;
133
134 INSTALL:
135         rts
136
137
138 ; ------------------------------------------------------------------------
139 ; UNINSTALL routine. Is called before the driver is removed from memory. May
140 ; clean up anything done by INSTALL but is probably empty most of the time.
141 ;
142 ; Must set an error code: NO
143 ;
144
145 UNINSTALL:
146         rts
147
148
149 ; ------------------------------------------------------------------------
150 ; INIT: Changes an already installed device from text mode to graphics
151 ; mode.
152 ; Note that INIT/DONE may be called multiple times while the driver
153 ; is loaded, while INSTALL is only called once, so any code that is needed
154 ; to initializes variables and so on must go here. Setting palette and
155 ; clearing the screen is not needed because this is called by the graphics
156 ; kernel later.
157 ; The graphics kernel will never call INIT when a graphics mode is already
158 ; active, so there is no need to protect against that.
159 ;
160 ; Must set an error code: YES
161 ;
162
163 INIT:
164
165 ; Initialize variables
166
167         ldx     #$FF
168         stx     BITMASK
169
170 ; Switch into graphics mode
171
172         lda     $DD02           ; Set the data direction regs
173         ora     #3
174         sta     $DD02
175         lda     $DD00
176         and     #$FC            ; Switch to bank 3
177         sta     $DD00
178
179         lda     $D018
180         sta     OLDD018
181         lda     #$48            ; Set color map to $D000, screen to $E000
182         sta     $D018
183
184         lda     $D011           ; And turn on bitmap
185         ora     #$20
186 DONE1:  sta     $D011
187
188 ; Done, reset the error code
189
190         lda     #TGI_ERR_OK
191         sta     ERROR
192         rts
193
194 ; ------------------------------------------------------------------------
195 ; DONE: Will be called to switch the graphics device back into text mode.
196 ; The graphics kernel will never call DONE when no graphics mode is active,
197 ; so there is no need to protect against that.
198 ;
199 ; Must set an error code: NO
200 ;
201
202 DONE:   lda     $DD02           ; Set the data direction regs
203         ora     #3
204         sta     $DD02
205         lda     $DD00
206         ora     #$03            ; Bank 0
207         sta     $DD00
208
209         lda     OLDD018         ; Screen mem --> $0400
210         sta     $D018
211
212         lda     $D011
213         and     #<~$20
214         sta     $D011
215         rts
216
217 ; ------------------------------------------------------------------------
218 ; GETERROR: Return the error code in A and clear it.
219
220 GETERROR:
221         ldx     #TGI_ERR_OK
222         lda     ERROR
223         stx     ERROR
224         rts
225
226 ; ------------------------------------------------------------------------
227 ; CONTROL: Platform/driver specific entry point.
228 ;
229 ; Must set an error code: YES
230 ;
231
232 CONTROL:
233         lda     #TGI_ERR_INV_FUNC
234         sta     ERROR
235         rts
236
237 ; ------------------------------------------------------------------------
238 ; CLEAR: Clears the screen.
239 ;
240 ; Must set an error code: NO
241 ;
242
243 CLEAR:  ldy     #$00
244         tya
245 @L1:    sta     VBASE+$0000,y
246         sta     VBASE+$0100,y
247         sta     VBASE+$0200,y
248         sta     VBASE+$0300,y
249         sta     VBASE+$0400,y
250         sta     VBASE+$0500,y
251         sta     VBASE+$0600,y
252         sta     VBASE+$0700,y
253         sta     VBASE+$0800,y
254         sta     VBASE+$0900,y
255         sta     VBASE+$0A00,y
256         sta     VBASE+$0B00,y
257         sta     VBASE+$0C00,y
258         sta     VBASE+$0D00,y
259         sta     VBASE+$0E00,y
260         sta     VBASE+$0F00,y
261         sta     VBASE+$1000,y
262         sta     VBASE+$1100,y
263         sta     VBASE+$1200,y
264         sta     VBASE+$1300,y
265         sta     VBASE+$1400,y
266         sta     VBASE+$1500,y
267         sta     VBASE+$1600,y
268         sta     VBASE+$1700,y
269         sta     VBASE+$1800,y
270         sta     VBASE+$1900,y
271         sta     VBASE+$1A00,y
272         sta     VBASE+$1B00,y
273         sta     VBASE+$1C00,y
274         sta     VBASE+$1D00,y
275         sta     VBASE+$1E00,y
276         sta     VBASE+$1F00,y
277         iny
278         bne     @L1
279         rts
280
281 ; ------------------------------------------------------------------------
282 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
283 ; The page number is already checked to be valid by the graphics kernel.
284 ;
285 ; Must set an error code: NO (will only be called if page ok)
286 ;
287
288 SETVIEWPAGE:
289         rts
290
291 ; ------------------------------------------------------------------------
292 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
293 ; The page number is already checked to be valid by the graphics kernel.
294 ;
295 ; Must set an error code: NO (will only be called if page ok)
296 ;
297
298 SETDRAWPAGE:
299         rts
300
301 ; ------------------------------------------------------------------------
302 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
303 ; to be in a valid range (0..maxcolor-1).
304 ;
305 ; Must set an error code: NO (will only be called if color ok)
306 ;
307
308 SETCOLOR:
309         tax
310         beq     @L1
311         lda     #$FF
312 @L1:    sta     BITMASK
313         rts
314
315 ; ------------------------------------------------------------------------
316 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
317 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
318 ; are not supported
319 ;
320 ; Must set an error code: YES
321 ;
322
323 SETPALETTE:
324         ldy     #PALETTESIZE - 1
325 @L1:    lda     (ptr1),y        ; Copy the palette
326         and     #$0F            ; Make a valid color
327         sta     PALETTE,y
328         dey
329         bpl     @L1
330
331 ; Get the color entries from the palette
332
333         lda     PALETTE+1       ; Foreground color
334         asl     a
335         asl     a
336         asl     a
337         asl     a
338         ora     PALETTE         ; Background color
339         tax
340
341 ; Initialize the color map with the new color settings (it is below the
342 ; I/O area)
343
344         ldy     #$00
345         sei
346         lda     $01             ; Get ROM config
347         pha                     ; Save it
348         and     #%11111100      ; Clear bit 0 and 1
349         sta     $01
350         txa                     ; Load color code
351 @L2:    sta     CBASE+$0000,y
352         sta     CBASE+$0100,y
353         sta     CBASE+$0200,y
354         sta     CBASE+$0300,y
355         iny
356         bne     @L2
357         pla
358         sta     $01
359         cli
360
361 ; Done, reset the error code
362
363         lda     #TGI_ERR_OK
364         sta     ERROR
365         rts
366
367 ; ------------------------------------------------------------------------
368 ; GETPALETTE: Return the current palette in A/X. Even drivers that cannot
369 ; set the palette should return the default palette here, so there's no
370 ; way for this function to fail.
371 ;
372 ; Must set an error code: NO
373 ;
374
375 GETPALETTE:
376         lda     #<PALETTE
377         ldx     #>PALETTE
378         rts
379
380 ; ------------------------------------------------------------------------
381 ; GETDEFPALETTE: Return the default palette for the driver in A/X. All
382 ; drivers should return something reasonable here, even drivers that don't
383 ; support palettes, otherwise the caller has no way to determine the colors
384 ; of the (not changeable) palette.
385 ;
386 ; Must set an error code: NO (all drivers must have a default palette)
387 ;
388
389 GETDEFPALETTE:
390         lda     #<DEFPALETTE
391         ldx     #>DEFPALETTE
392         rts
393
394 ; ------------------------------------------------------------------------
395 ; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
396 ; color. The coordinates passed to this function are never outside the
397 ; visible screen area, so there is no need for clipping inside this function.
398 ;
399 ; Must set an error code: NO
400 ;
401
402 SETPIXEL:
403         jsr     CALC            ; Calculate coordinates
404
405         sei                     ; Get underneath ROM
406         lda     $01
407         pha
408         lda     #$34
409         sta     $01
410
411         lda     (POINT),Y
412         eor     BITMASK
413         and     BITTAB,X
414         eor     (POINT),Y
415         sta     (POINT),Y
416
417         pla
418         sta     $01
419         cli
420
421 @L9:    rts
422
423 ; ------------------------------------------------------------------------
424 ; GETPIXEL: Read the color value of a pixel and return it in A/X. The
425 ; coordinates passed to this function are never outside the visible screen
426 ; area, so there is no need for clipping inside this function.
427
428
429 GETPIXEL:
430         jsr     CALC            ; Calculate coordinates
431
432         sei                     ; Get underneath ROM
433         lda     $01
434         pha
435         lda     #$34
436         sta     $01
437
438         lda     (POINT),Y
439         ldy     #$00
440         and     BITTAB,X
441         beq     @L1
442         iny
443
444 @L1:    pla
445         sta     $01
446         cli
447
448         tya                     ; Get color value into A
449         ldx     #$00            ; Clear high byte
450         rts
451
452 ; ------------------------------------------------------------------------
453 ; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
454 ; X2/Y2 = ptr3/ptr4 using the current drawing color.
455 ;
456 ; To deal with off-screen coordinates, the current row
457 ; and column (40x25) is kept track of.  These are set
458 ; negative when the point is off the screen, and made
459 ; positive when the point is within the visible screen.
460 ;
461 ; X1,X2 etc. are set up above (x2=LINNUM in particular)
462 ; Format is LINE x2,y2,x1,y1
463 ;
464 ; Must set an error code: NO
465 ;
466
467 LINE:
468
469 @CHECK: lda     X2           ;Make sure x1<x2
470         sec
471         sbc     X1
472         tax
473         lda     X2+1
474         sbc     X1+1
475         bpl     @CONT
476         lda     Y2           ;If not, swap P1 and P2
477         ldy     Y1
478         sta     Y1
479         sty     Y2
480         lda     Y2+1
481         ldy     Y1+1
482         sta     Y1+1
483         sty     Y2+1
484         lda     X1
485         ldy     X2
486         sty     X1
487         sta     X2
488         lda     X2+1
489         ldy     X1+1
490         sta     X1+1
491         sty     X2+1
492         bcc     @CHECK
493
494 @CONT:  sta     DX+1
495         stx     DX
496
497         ldx     #$C8         ;INY
498         lda     Y2           ;Calculate dy
499         sec
500         sbc     Y1
501         tay
502         lda     Y2+1
503         sbc     Y1+1
504         bpl     @DYPOS       ;Is y2>=y1?
505         lda     Y1           ;Otherwise dy=y1-y2
506         sec
507         sbc     Y2
508         tay
509         ldx     #$88         ;DEY
510
511 @DYPOS: sty     DY              ; 8-bit DY -- FIX ME?
512         stx     YINCDEC
513         stx     XINCDEC
514
515         jsr     CALC            ; Set up .X,.Y,POINT, and INRANGE
516         lda     BITCHUNK,X
517         sta     OLDCHUNK
518         sta     CHUNK
519
520         sei                     ; Get underneath ROM
521         lda     #$34
522         sta     $01
523
524         ldx     DY
525         cpx     DX           ;Who's bigger: dy or dx?
526         bcc     STEPINX      ;If dx, then...
527         lda     DX+1
528         bne     STEPINX
529
530 ;
531 ; Big steps in Y
532 ;
533 ;   To simplify my life, just use PLOT to plot points.
534 ;
535 ;   No more!
536 ;   Added special plotting routine -- cool!
537 ;
538 ;   X is now counter, Y is y-coordinate
539 ;
540 ; On entry, X=DY=number of loop iterations, and Y=
541 ;   Y1 AND #$07
542 STEPINY:
543         lda     #00
544         sta     OLDCHUNK     ;So plotting routine will work right
545         lda     CHUNK
546         lsr                  ;Strip the bit
547         eor     CHUNK
548         sta     CHUNK
549         txa
550         bne     @CONT        ;If dy=0 it's just a point
551         inx
552 @CONT:  lsr                  ;Init counter to dy/2
553 ;
554 ; Main loop
555 ;
556 YLOOP:  sta     TEMP
557
558         lda     INRANGE      ;Range check
559         bne     @SKIP
560
561         lda     (POINT),y    ;Otherwise plot
562         eor     BITMASK
563         and     CHUNK
564         eor     (POINT),y
565         sta     (POINT),y
566 @SKIP:
567 YINCDEC:
568         iny                  ;Advance Y coordinate
569         cpy     #8
570         bcc     @CONT        ;No prob if Y=0..7
571         jsr     FIXY
572 @CONT:  lda     TEMP         ;Restore A
573         sec
574         sbc     DX
575         bcc     YFIXX
576 YCONT:  dex                  ;X is counter
577         bne     YLOOP
578 YCONT2: lda     (POINT),y    ;Plot endpoint
579         eor     BITMASK
580         and     CHUNK
581         eor     (POINT),y
582         sta     (POINT),y
583 YDONE:  lda     #$36
584         sta     $01
585         cli
586         rts
587
588 YFIXX:                    ;x=x+1
589         adc     DY
590         lsr     CHUNK
591         bne     YCONT        ;If we pass a column boundary...
592         ror     CHUNK        ;then reset CHUNK to $80
593         sta     TEMP2
594         lda     COL
595         bmi     @C1          ;Skip if column is negative
596         cmp     #39          ;End if move past end of screen
597         bcs     YDONE
598 @C1:    lda     POINT        ;And add 8 to POINT
599         adc     #8
600         sta     POINT
601         bcc     @CONT
602         inc     POINT+1
603 @CONT:  inc     COL          ;Increment column
604         bne     @C2
605         lda     ROW          ;Range check
606         cmp     #25
607         bcs     @C2
608         lda     #00          ;Passed into col 0
609         sta     INRANGE
610 @C2:    lda     TEMP2
611         dex
612         bne     YLOOP
613         beq     YCONT2
614
615 ;
616 ; Big steps in X direction
617 ;
618 ; On entry, X=DY=number of loop iterations, and Y=
619 ;   Y1 AND #$07
620
621 .bss
622 COUNTHI:
623         .byte   $00       ;Temporary counter
624                           ;only used once
625 .code
626 STEPINX:
627         ldx     DX
628         lda     DX+1
629         sta     COUNTHI
630         cmp     #$80
631         ror                  ;Need bit for initialization
632         sta     Y1           ;High byte of counter
633         txa
634         bne     @CONT        ;Could be $100
635         dec     COUNTHI
636 @CONT:  ror
637 ;
638 ; Main loop
639 ;
640 XLOOP:  lsr     CHUNK
641         beq     XFIXC        ;If we pass a column boundary...
642 XCONT1: sbc     DY
643         bcc     XFIXY        ;Time to step in Y?
644 XCONT2: dex
645         bne     XLOOP
646         dec     COUNTHI      ;High bits set?
647         bpl     XLOOP
648
649 XDONE:  lsr     CHUNK        ;Advance to last point
650         jsr     LINEPLOT     ;Plot the last chunk
651 EXIT:   lda     #$36
652         sta     $01
653         cli
654         rts
655 ;
656 ; CHUNK has passed a column, so plot and increment pointer
657 ; and fix up CHUNK, OLDCHUNK.
658 ;
659 XFIXC:  sta     TEMP
660         jsr     LINEPLOT
661         lda     #$FF
662         sta     CHUNK
663         sta     OLDCHUNK
664         lda     COL
665         bmi     @C1          ;Skip if column is negative
666         cmp     #39          ;End if move past end of screen
667         bcs     EXIT
668 @C1:    lda     POINT
669         adc     #8
670         sta     POINT
671         bcc     @CONT
672         inc     POINT+1
673 @CONT:  inc     COL
674         bne     @C2
675         lda     ROW
676         cmp     #25
677         bcs     @C2
678         lda     #00
679         sta     INRANGE
680 @C2:    lda     TEMP
681         sec
682         bcs     XCONT1
683 ;
684 ; Check to make sure there isn't a high bit, plot chunk,
685 ; and update Y-coordinate.
686 ;
687 XFIXY:  dec     Y1           ;Maybe high bit set
688         bpl     XCONT2
689         adc     DX
690         sta     TEMP
691         lda     DX+1
692         adc     #$FF         ;Hi byte
693         sta     Y1
694
695         jsr     LINEPLOT     ;Plot chunk
696         lda     CHUNK
697         sta     OLDCHUNK
698
699         lda     TEMP
700 XINCDEC:
701         iny                  ;Y-coord
702         cpy     #8           ;0..7 is ok
703         bcc     XCONT2
704         sta     TEMP
705         jsr     FIXY
706         lda     TEMP
707         jmp     XCONT2
708
709 ;
710 ; Subroutine to plot chunks/points (to save a little
711 ; room, gray hair, etc.)
712 ;
713 LINEPLOT:                       ; Plot the line chunk
714         lda     INRANGE
715         bne     @SKIP
716
717         lda     (POINT),Y       ; Otherwise plot
718         eor     BITMASK
719         ora     CHUNK
720         and     OLDCHUNK
721         eor     CHUNK
722         eor     (POINT),Y
723         sta     (POINT),Y
724 @SKIP:  rts
725
726 ;
727 ; Subroutine to fix up pointer when Y decreases through
728 ; zero or increases through 7.
729 ;
730 FIXY:   cpy     #255         ;Y=255 or Y=8
731         beq     @DECPTR
732 @INCPTR:                     ;Add 320 to pointer
733         ldy     #0           ;Y increased through 7
734         lda     ROW
735         bmi     @C1          ;If negative, then don't update
736         cmp     #24
737         bcs     @TOAST       ;If at bottom of screen then quit
738 @C1:    lda     POINT
739         adc     #<320
740         sta     POINT
741         lda     POINT+1
742         adc     #>320
743         sta     POINT+1
744 @CONT1: inc     ROW
745         bne     @DONE
746         lda     COL
747         bpl     @CLEAR
748 @DONE:  rts
749
750 @DECPTR:                     ;Okay, subtract 320 then
751         ldy     #7           ;Y decreased through 0
752         lda     POINT
753         sec
754         sbc     #<320
755         sta     POINT
756         lda     POINT+1
757         sbc     #>320
758         sta     POINT+1
759 @CONT2: dec     ROW
760         bmi     @TOAST
761         lda     ROW
762         cmp     #24
763         bne     @DONE
764         lda     COL
765         bmi     @DONE
766 @CLEAR: lda     #00
767         sta     INRANGE
768         rts
769
770 @TOAST: pla                  ;Remove old return address
771         pla
772         jmp     EXIT         ;Restore interrupts, etc.
773
774 ; ------------------------------------------------------------------------
775 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
776 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
777 ; Contrary to most other functions, the graphics kernel will sort and clip
778 ; the coordinates before calling the driver, so on entry the following
779 ; conditions are valid:
780 ;       X1 <= X2
781 ;       Y1 <= Y2
782 ;       (X1 >= 0) && (X1 < XRES)
783 ;       (X2 >= 0) && (X2 < XRES)
784 ;       (Y1 >= 0) && (Y1 < YRES)
785 ;       (Y2 >= 0) && (Y2 < YRES)
786 ;
787 ; Must set an error code: NO
788 ;
789
790 ; Note: This function needs optimization. It's just a cheap translation of
791 ; the original C wrapper and could be written much smaller (besides that,
792 ; calling LINE is not a good idea either).
793
794 BAR:    lda     Y2
795         sta     Y2SAVE
796         lda     Y2+1
797         sta     Y2SAVE+1
798
799         lda     X2
800         sta     X2SAVE
801         lda     X2+1
802         sta     X2SAVE+1
803
804         lda     Y1
805         sta     Y1SAVE
806         lda     Y1+1
807         sta     Y1SAVE+1
808
809         lda     X1
810         sta     X1SAVE
811         lda     X1+1
812         sta     X1SAVE+1
813
814 @L1:    lda     Y1
815         sta     Y2
816         lda     Y1+1
817         sta     Y2+1
818         jsr     LINE
819
820         lda     Y1SAVE
821         cmp     Y2SAVE
822         bne     @L2
823         lda     Y1SAVE
824         cmp     Y2SAVE
825         beq     @L4
826
827 @L2:    inc     Y1SAVE
828         bne     @L3
829         inc     Y1SAVE+1
830
831 @L3:    lda     Y1SAVE
832         sta     Y1
833         lda     Y1SAVE+1
834         sta     Y1+1
835
836         lda     X1SAVE
837         sta     X1
838         lda     X1SAVE+1
839         sta     X1+1
840
841         lda     X2SAVE
842         sta     X2
843         lda     X2SAVE+1
844         sta     X2+1
845         jmp     @L1
846
847 @L4:    rts
848
849
850 ; ------------------------------------------------------------------------
851 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
852 ; direction is passend in X/Y, the text direction is passed in A.
853 ;
854 ; Must set an error code: NO
855 ;
856
857 TEXTSTYLE:
858         stx     TEXTMAGX
859         sty     TEXTMAGY
860         sta     TEXTDIR
861         rts
862
863
864 ; ------------------------------------------------------------------------
865 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
866 ; current text style. The text to output is given as a zero terminated
867 ; string with address in ptr3.
868 ;
869 ; Must set an error code: NO
870 ;
871
872 OUTTEXT:
873
874 ; Calculate a pointer to the representation of the character in the
875 ; character ROM 
876
877         ldx     #((>(CHARROM + $0800)) >> 3)
878         ldy     #0
879         lda     (TEXT),y
880         bmi     @L1
881         ldx     #((>(CHARROM + $0000)) >> 3)
882 @L1:    stx     ptr4+1
883         asl     a
884         rol     ptr4+1
885         asl     a
886         rol     ptr4+1
887         asl     a
888         rol     ptr4+1
889         sta     ptr4
890
891
892
893
894
895         rts
896
897 ; ------------------------------------------------------------------------
898 ; Calculate all variables to plot the pixel at X1/Y1. If the point is out
899 ; of range, a carry is returned and INRANGE is set to a value !0 zero. If
900 ; the coordinates are valid, INRANGE is zero and the carry clear.
901
902 CALC:   lda     Y1
903         sta     ROW
904         and     #7
905         tay
906         lda     Y1+1
907         lsr                     ; Neg is possible
908         ror     ROW
909         lsr
910         ror     ROW
911         lsr
912         ror     ROW
913
914         lda     #00
915         sta     POINT
916         lda     ROW
917         cmp     #$80
918         ror
919         ror     POINT
920         cmp     #$80
921         ror
922         ror     POINT           ; row*64
923         adc     ROW             ; +row*256
924         clc
925         adc     #>VBASE         ; +bitmap base
926         sta     POINT+1
927
928         lda     X1
929         tax
930         sta     COL
931         lda     X1+1
932         lsr
933         ror     COL
934         lsr
935         ror     COL
936         lsr
937         ror     COL
938
939         txa
940         and     #$F8
941         clc
942         adc     POINT           ; +(X AND #$F8)
943         sta     POINT
944         lda     X1+1
945         adc     POINT+1
946         sta     POINT+1
947         txa
948         and     #7
949         tax
950
951         lda     ROW
952         cmp     #25
953         bcs     @L9
954         lda     COL
955         cmp     #40
956         bcs     @L9
957         lda     #00
958 @L9:    sta     INRANGE
959         rts
960
961