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