]> git.sur5r.net Git - cc65/blob - libsrc/c64/c64-320-200-2.s
New loadable mouse drivers
[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-mode.inc"
11         .include        "tgi-error.inc"
12
13
14         .macpack        generic
15
16
17 ; ------------------------------------------------------------------------
18 ; Header. Includes jump table and constants.
19
20 .segment        "JUMPTABLE"
21
22 ; First part of the header is a structure that has a magic and defines the
23 ; capabilities of the driver
24
25         .byte   $74, $67, $69           ; "tgi"
26         .byte   TGI_API_VERSION         ; TGI API version number
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         .res    4, $00                  ; Reserved for future extensions
34
35 ; Next comes the jump table. Currently all entries must be valid and may point
36 ; to an RTS for test versions (function not implemented). A future version may
37 ; allow for emulation: In this case the vector will be zero. Emulation means
38 ; that the graphics kernel will emulate the function by using lower level
39 ; primitives - for example ploting a line by using calls to SETPIXEL.
40
41         .word   INSTALL
42         .word   UNINSTALL
43         .word   INIT
44         .word   DONE
45         .word   GETERROR
46         .word   CONTROL
47         .word   CLEAR
48         .word   SETVIEWPAGE
49         .word   SETDRAWPAGE
50         .word   SETCOLOR
51         .word   SETPALETTE
52         .word   GETPALETTE
53         .word   GETDEFPALETTE
54         .word   SETPIXEL
55         .word   GETPIXEL
56         .word   LINE
57         .word   BAR
58         .word   CIRCLE
59         .word   TEXTSTYLE
60         .word   OUTTEXT
61
62 ; ------------------------------------------------------------------------
63 ; Data.
64
65 ; Variables mapped to the zero page segment variables. Some of these are
66 ; used for passing parameters to the driver.
67
68 X1              := ptr1
69 Y1              := ptr2
70 X2              := ptr3
71 Y2              := ptr4
72 RADIUS          := tmp1
73
74 ROW             := tmp2         ; Bitmap row...
75 COL             := tmp3         ; ...and column, both set by PLOT
76 TEMP            := tmp4
77 TEMP2           := sreg
78 POINT           := regsave
79 INRANGE         := regsave+2    ; PLOT variable, $00 = coordinates in range
80
81 CHUNK           := X2           ; Used in the line routine
82 OLDCHUNK        := X2+1         ; Dito
83
84 ; Absolute variables used in the code
85
86 .bss
87
88 ERROR:          .res    1       ; Error code
89 PALETTE:        .res    2       ; The current palette
90
91 BITMASK:        .res    1       ; $00 = clear, $FF = set pixels
92
93 ; INIT/DONE
94 OLDD018:        .res    1       ; Old register value
95
96 ; Line routine stuff
97 DX:             .res    2
98 DY:             .res    2
99
100 ; Circle routine stuff, overlaid by BAR variables
101 X1SAVE:
102 CURX:           .res    1
103 CURY:           .res    1
104 Y1SAVE:
105 BROW:           .res    1       ; Bottom row
106 TROW:           .res    1       ; Top row
107 X2SAVE:
108 LCOL:           .res    1       ; Left column
109 RCOL:           .res    1       ; Right column
110 Y2SAVE:
111 CHUNK1:         .res    1
112 OLDCH1:         .res    1
113 CHUNK2:         .res    1
114 OLDCH2:         .res    1
115
116 ; Text output stuff
117 TEXTMAGX:       .res    1
118 TEXTMAGY:       .res    1
119 TEXTDIR:        .res    1
120
121 ; Constants and tables
122
123 .rodata
124
125 DEFPALETTE:     .byte   $00, $01        ; White on black
126 PALETTESIZE     = * - DEFPALETTE
127
128 BITTAB:         .byte   $80,$40,$20,$10,$08,$04,$02,$01
129 BITCHUNK:       .byte   $FF,$7F,$3F,$1F,$0F,$07,$03,$01
130
131 VBASE           = $E000         ; Video memory base address
132 CBASE           = $D000         ; Color memory base address
133
134
135 .code
136
137 ; ------------------------------------------------------------------------
138 ; INSTALL routine. Is called after the driver is loaded into memory. May
139 ; initialize anything that has to be done just once. Is probably empty
140 ; most of the time.
141 ;
142 ; Must set an error code: NO
143 ;
144
145 INSTALL:
146         rts
147
148
149 ; ------------------------------------------------------------------------
150 ; UNINSTALL routine. Is called before the driver is removed from memory. May
151 ; clean up anything done by INSTALL but is probably empty most of the time.
152 ;
153 ; Must set an error code: NO
154 ;
155
156 UNINSTALL:
157         rts
158
159
160 ; ------------------------------------------------------------------------
161 ; INIT: Changes an already installed device from text mode to graphics
162 ; mode.
163 ; Note that INIT/DONE may be called multiple times while the driver
164 ; is loaded, while INSTALL is only called once, so any code that is needed
165 ; to initializes variables and so on must go here. Setting palette and
166 ; clearing the screen is not needed because this is called by the graphics
167 ; kernel later.
168 ; The graphics kernel will never call INIT when a graphics mode is already
169 ; active, so there is no need to protect against that.
170 ;
171 ; Must set an error code: YES
172 ;
173
174 INIT:
175
176 ; Initialize variables
177
178         ldx     #$FF
179         stx     BITMASK
180
181 ; Switch into graphics mode
182
183         lda     $DD02           ; Set the data direction regs
184         ora     #3
185         sta     $DD02
186         lda     $DD00
187         and     #$FC            ; Switch to bank 3
188         sta     $DD00
189
190         lda     $D018
191         sta     OLDD018
192         lda     #$48            ; Set color map to $D000, screen to $E000
193         sta     $D018
194
195         lda     $D011           ; And turn on bitmap
196         ora     #$20
197 DONE1:  sta     $D011
198
199 ; Done, reset the error code
200
201         lda     #TGI_ERR_OK
202         sta     ERROR
203         rts
204
205 ; ------------------------------------------------------------------------
206 ; DONE: Will be called to switch the graphics device back into text mode.
207 ; The graphics kernel will never call DONE when no graphics mode is active,
208 ; so there is no need to protect against that.
209 ;
210 ; Must set an error code: NO
211 ;
212
213 DONE:   lda     $DD02           ; Set the data direction regs
214         ora     #3
215         sta     $DD02
216         lda     $DD00
217         ora     #$03            ; Bank 0
218         sta     $DD00
219
220         lda     OLDD018         ; Screen mem --> $0400
221         sta     $D018
222
223         lda     $D011
224         and     #<~$20
225         sta     $D011
226         rts
227
228 ; ------------------------------------------------------------------------
229 ; GETERROR: Return the error code in A and clear it.
230
231 GETERROR:
232         ldx     #TGI_ERR_OK
233         lda     ERROR
234         stx     ERROR
235         rts
236
237 ; ------------------------------------------------------------------------
238 ; CONTROL: Platform/driver specific entry point.
239 ;
240 ; Must set an error code: YES
241 ;
242
243 CONTROL:
244         lda     #TGI_ERR_INV_FUNC
245         sta     ERROR
246         rts
247
248 ; ------------------------------------------------------------------------
249 ; CLEAR: Clears the screen.
250 ;
251 ; Must set an error code: NO
252 ;
253
254 CLEAR:  ldy     #$00
255         tya
256 @L1:    sta     VBASE+$0000,y
257         sta     VBASE+$0100,y
258         sta     VBASE+$0200,y
259         sta     VBASE+$0300,y
260         sta     VBASE+$0400,y
261         sta     VBASE+$0500,y
262         sta     VBASE+$0600,y
263         sta     VBASE+$0700,y
264         sta     VBASE+$0800,y
265         sta     VBASE+$0900,y
266         sta     VBASE+$0A00,y
267         sta     VBASE+$0B00,y
268         sta     VBASE+$0C00,y
269         sta     VBASE+$0D00,y
270         sta     VBASE+$0E00,y
271         sta     VBASE+$0F00,y
272         sta     VBASE+$1000,y
273         sta     VBASE+$1100,y
274         sta     VBASE+$1200,y
275         sta     VBASE+$1300,y
276         sta     VBASE+$1400,y
277         sta     VBASE+$1500,y
278         sta     VBASE+$1600,y
279         sta     VBASE+$1700,y
280         sta     VBASE+$1800,y
281         sta     VBASE+$1900,y
282         sta     VBASE+$1A00,y
283         sta     VBASE+$1B00,y
284         sta     VBASE+$1C00,y
285         sta     VBASE+$1D00,y
286         sta     VBASE+$1E00,y
287         sta     VBASE+$1F00,y
288         iny
289         bne     @L1
290         rts
291
292 ; ------------------------------------------------------------------------
293 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
294 ; The page number is already checked to be valid by the graphics kernel.
295 ;
296 ; Must set an error code: NO (will only be called if page ok)
297 ;
298
299 SETVIEWPAGE:
300         rts
301
302 ; ------------------------------------------------------------------------
303 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
304 ; The page number is already checked to be valid by the graphics kernel.
305 ;
306 ; Must set an error code: NO (will only be called if page ok)
307 ;
308
309 SETDRAWPAGE:
310         rts
311
312 ; ------------------------------------------------------------------------
313 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
314 ; to be in a valid range (0..maxcolor-1).
315 ;
316 ; Must set an error code: NO (will only be called if color ok)
317 ;
318
319 SETCOLOR:
320         tax
321         beq     @L1
322         lda     #$FF
323 @L1:    sta     BITMASK
324         rts
325
326 ; ------------------------------------------------------------------------
327 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
328 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
329 ; are not supported
330 ;
331 ; Must set an error code: YES
332 ;
333
334 SETPALETTE:
335         ldy     #PALETTESIZE - 1
336 @L1:    lda     (ptr1),y        ; Copy the palette
337         and     #$0F            ; Make a valid color
338         sta     PALETTE,y
339         dey
340         bpl     @L1
341
342 ; Get the color entries from the palette
343
344         lda     PALETTE+1       ; Foreground color
345         asl     a
346         asl     a
347         asl     a
348         asl     a
349         ora     PALETTE         ; Background color
350         tax
351
352 ; Initialize the color map with the new color settings (it is below the
353 ; I/O area)
354
355         ldy     #$00
356         sei
357         lda     $01             ; Get ROM config
358         pha                     ; Save it
359         and     #%11111100      ; Clear bit 0 and 1
360         sta     $01
361         txa                     ; Load color code
362 @L2:    sta     CBASE+$0000,y
363         sta     CBASE+$0100,y
364         sta     CBASE+$0200,y
365         sta     CBASE+$0300,y
366         iny
367         bne     @L2
368         pla
369         sta     $01
370         cli
371
372 ; Done, reset the error code
373
374         lda     #TGI_ERR_OK
375         sta     ERROR
376         rts
377
378 ; ------------------------------------------------------------------------
379 ; GETPALETTE: Return the current palette in A/X. Even drivers that cannot
380 ; set the palette should return the default palette here, so there's no
381 ; way for this function to fail.
382 ;
383 ; Must set an error code: NO
384 ;
385
386 GETPALETTE:
387         lda     #<PALETTE
388         ldx     #>PALETTE
389         rts
390
391 ; ------------------------------------------------------------------------
392 ; GETDEFPALETTE: Return the default palette for the driver in A/X. All
393 ; drivers should return something reasonable here, even drivers that don't
394 ; support palettes, otherwise the caller has no way to determine the colors
395 ; of the (not changeable) palette.
396 ;
397 ; Must set an error code: NO (all drivers must have a default palette)
398 ;
399
400 GETDEFPALETTE:
401         lda     #<DEFPALETTE
402         ldx     #>DEFPALETTE
403         rts
404
405 ; ------------------------------------------------------------------------
406 ; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
407 ; color. The coordinates passed to this function are never outside the
408 ; visible screen area, so there is no need for clipping inside this function.
409 ;
410 ; Must set an error code: NO
411 ;
412
413 SETPIXEL:
414         jsr     CALC            ; Calculate coordinates
415
416         sei                     ; Get underneath ROM
417         lda     $01
418         pha
419         lda     #$34
420         sta     $01
421
422         lda     (POINT),Y
423         eor     BITMASK
424         and     BITTAB,X
425         eor     (POINT),Y
426         sta     (POINT),Y
427
428         pla
429         sta     $01
430         cli
431
432 @L9:    rts
433
434 ; ------------------------------------------------------------------------
435 ; GETPIXEL: Read the color value of a pixel and return it in A/X. The
436 ; coordinates passed to this function are never outside the visible screen
437 ; area, so there is no need for clipping inside this function.
438
439
440 GETPIXEL:
441         jsr     CALC            ; Calculate coordinates
442
443         sei                     ; Get underneath ROM
444         lda     $01
445         pha
446         lda     #$34
447         sta     $01
448
449         lda     (POINT),Y
450         ldy     #$00
451         and     BITTAB,X
452         beq     @L1
453         iny
454
455 @L1:    pla
456         sta     $01
457         cli
458
459         tya                     ; Get color value into A
460         ldx     #$00            ; Clear high byte
461         rts
462
463 ; ------------------------------------------------------------------------
464 ; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
465 ; X2/Y2 = ptr3/ptr4 using the current drawing color.
466 ;
467 ; To deal with off-screen coordinates, the current row
468 ; and column (40x25) is kept track of.  These are set
469 ; negative when the point is off the screen, and made
470 ; positive when the point is within the visible screen.
471 ;
472 ; X1,X2 etc. are set up above (x2=LINNUM in particular)
473 ; Format is LINE x2,y2,x1,y1
474 ;
475 ; Must set an error code: NO
476 ;
477
478 LINE:
479
480 @CHECK: lda     X2           ;Make sure x1<x2
481         sec
482         sbc     X1
483         tax
484         lda     X2+1
485         sbc     X1+1
486         bpl     @CONT
487         lda     Y2           ;If not, swap P1 and P2
488         ldy     Y1
489         sta     Y1
490         sty     Y2
491         lda     Y2+1
492         ldy     Y1+1
493         sta     Y1+1
494         sty     Y2+1
495         lda     X1
496         ldy     X2
497         sty     X1
498         sta     X2
499         lda     X2+1
500         ldy     X1+1
501         sta     X1+1
502         sty     X2+1
503         bcc     @CHECK
504
505 @CONT:  sta     DX+1
506         stx     DX
507
508         ldx     #$C8         ;INY
509         lda     Y2           ;Calculate dy
510         sec
511         sbc     Y1
512         tay
513         lda     Y2+1
514         sbc     Y1+1
515         bpl     @DYPOS       ;Is y2>=y1?
516         lda     Y1           ;Otherwise dy=y1-y2
517         sec
518         sbc     Y2
519         tay
520         ldx     #$88         ;DEY
521
522 @DYPOS: sty     DY              ; 8-bit DY -- FIX ME?
523         stx     YINCDEC
524         stx     XINCDEC
525
526         jsr     CALC            ; Set up .X,.Y,POINT, and INRANGE
527         lda     BITCHUNK,X
528         sta     OLDCHUNK
529         sta     CHUNK
530
531         sei                     ; Get underneath ROM
532         lda     #$34
533         sta     $01
534
535         ldx     DY
536         cpx     DX           ;Who's bigger: dy or dx?
537         bcc     STEPINX      ;If dx, then...
538         lda     DX+1
539         bne     STEPINX
540
541 ;
542 ; Big steps in Y
543 ;
544 ;   To simplify my life, just use PLOT to plot points.
545 ;
546 ;   No more!
547 ;   Added special plotting routine -- cool!
548 ;
549 ;   X is now counter, Y is y-coordinate
550 ;
551 ; On entry, X=DY=number of loop iterations, and Y=
552 ;   Y1 AND #$07
553 STEPINY:
554         lda     #00
555         sta     OLDCHUNK     ;So plotting routine will work right
556         lda     CHUNK
557         lsr                  ;Strip the bit
558         eor     CHUNK
559         sta     CHUNK
560         txa
561         bne     @CONT        ;If dy=0 it's just a point
562         inx
563 @CONT:  lsr                  ;Init counter to dy/2
564 ;
565 ; Main loop
566 ;
567 YLOOP:  sta     TEMP
568
569         lda     INRANGE      ;Range check
570         bne     @SKIP
571
572         lda     (POINT),y    ;Otherwise plot
573         eor     BITMASK
574         and     CHUNK
575         eor     (POINT),y
576         sta     (POINT),y
577 @SKIP:
578 YINCDEC:
579         iny                  ;Advance Y coordinate
580         cpy     #8
581         bcc     @CONT        ;No prob if Y=0..7
582         jsr     FIXY
583 @CONT:  lda     TEMP         ;Restore A
584         sec
585         sbc     DX
586         bcc     YFIXX
587 YCONT:  dex                  ;X is counter
588         bne     YLOOP
589 YCONT2: lda     (POINT),y    ;Plot endpoint
590         eor     BITMASK
591         and     CHUNK
592         eor     (POINT),y
593         sta     (POINT),y
594 YDONE:  lda     #$37
595         sta     $01
596         cli
597         rts
598
599 YFIXX:                    ;x=x+1
600         adc     DY
601         lsr     CHUNK
602         bne     YCONT        ;If we pass a column boundary...
603         ror     CHUNK        ;then reset CHUNK to $80
604         sta     TEMP2
605         lda     COL
606         bmi     @C1          ;Skip if column is negative
607         cmp     #39          ;End if move past end of screen
608         bcs     YDONE
609 @C1:    lda     POINT        ;And add 8 to POINT
610         adc     #8
611         sta     POINT
612         bcc     @CONT
613         inc     POINT+1
614 @CONT:  inc     COL          ;Increment column
615         bne     @C2
616         lda     ROW          ;Range check
617         cmp     #25
618         bcs     @C2
619         lda     #00          ;Passed into col 0
620         sta     INRANGE
621 @C2:    lda     TEMP2
622         dex
623         bne     YLOOP
624         beq     YCONT2
625
626 ;
627 ; Big steps in X direction
628 ;
629 ; On entry, X=DY=number of loop iterations, and Y=
630 ;   Y1 AND #$07
631
632 .bss
633 COUNTHI:
634         .byte   $00       ;Temporary counter
635                           ;only used once
636 .code
637 STEPINX:
638         ldx     DX
639         lda     DX+1
640         sta     COUNTHI
641         cmp     #$80
642         ror                  ;Need bit for initialization
643         sta     Y1           ;High byte of counter
644         txa
645         bne     @CONT        ;Could be $100
646         dec     COUNTHI
647 @CONT:  ror
648 ;
649 ; Main loop
650 ;
651 XLOOP:  lsr     CHUNK
652         beq     XFIXC        ;If we pass a column boundary...
653 XCONT1: sbc     DY
654         bcc     XFIXY        ;Time to step in Y?
655 XCONT2: dex
656         bne     XLOOP
657         dec     COUNTHI      ;High bits set?
658         bpl     XLOOP
659
660 XDONE:  lsr     CHUNK        ;Advance to last point
661         jsr     LINEPLOT     ;Plot the last chunk
662 EXIT:   lda     #$37
663         sta     $01
664         cli
665         rts
666 ;
667 ; CHUNK has passed a column, so plot and increment pointer
668 ; and fix up CHUNK, OLDCHUNK.
669 ;
670 XFIXC:  sta     TEMP
671         jsr     LINEPLOT
672         lda     #$FF
673         sta     CHUNK
674         sta     OLDCHUNK
675         lda     COL
676         bmi     @C1          ;Skip if column is negative
677         cmp     #39          ;End if move past end of screen
678         bcs     EXIT
679 @C1:    lda     POINT
680         adc     #8
681         sta     POINT
682         bcc     @CONT
683         inc     POINT+1
684 @CONT:  inc     COL
685         bne     @C2
686         lda     ROW
687         cmp     #25
688         bcs     @C2
689         lda     #00
690         sta     INRANGE
691 @C2:    lda     TEMP
692         sec
693         bcs     XCONT1
694 ;
695 ; Check to make sure there isn't a high bit, plot chunk,
696 ; and update Y-coordinate.
697 ;
698 XFIXY:  dec     Y1           ;Maybe high bit set
699         bpl     XCONT2
700         adc     DX
701         sta     TEMP
702         lda     DX+1
703         adc     #$FF         ;Hi byte
704         sta     Y1
705
706         jsr     LINEPLOT     ;Plot chunk
707         lda     CHUNK
708         sta     OLDCHUNK
709
710         lda     TEMP
711 XINCDEC:
712         iny                  ;Y-coord
713         cpy     #8           ;0..7 is ok
714         bcc     XCONT2
715         sta     TEMP
716         jsr     FIXY
717         lda     TEMP
718         jmp     XCONT2
719
720 ;
721 ; Subroutine to plot chunks/points (to save a little
722 ; room, gray hair, etc.)
723 ;
724 LINEPLOT:                       ; Plot the line chunk
725         lda     INRANGE
726         bne     @SKIP
727
728         lda     (POINT),Y       ; Otherwise plot
729         eor     BITMASK
730         ora     CHUNK
731         and     OLDCHUNK
732         eor     CHUNK
733         eor     (POINT),Y
734         sta     (POINT),Y
735 @SKIP:  rts
736
737 ;
738 ; Subroutine to fix up pointer when Y decreases through
739 ; zero or increases through 7.
740 ;
741 FIXY:   cpy     #255         ;Y=255 or Y=8
742         beq     @DECPTR
743 @INCPTR:                     ;Add 320 to pointer
744         ldy     #0           ;Y increased through 7
745         lda     ROW
746         bmi     @C1          ;If negative, then don't update
747         cmp     #24
748         bcs     @TOAST       ;If at bottom of screen then quit
749 @C1:    lda     POINT
750         adc     #<320
751         sta     POINT
752         lda     POINT+1
753         adc     #>320
754         sta     POINT+1
755 @CONT1: inc     ROW
756         bne     @DONE
757         lda     COL
758         bpl     @CLEAR
759 @DONE:  rts
760
761 @DECPTR:                     ;Okay, subtract 320 then
762         ldy     #7           ;Y decreased through 0
763         lda     POINT
764         sec
765         sbc     #<320
766         sta     POINT
767         lda     POINT+1
768         sbc     #>320
769         sta     POINT+1
770 @CONT2: dec     ROW
771         bmi     @TOAST
772         lda     ROW
773         cmp     #24
774         bne     @DONE
775         lda     COL
776         bmi     @DONE
777 @CLEAR: lda     #00
778         sta     INRANGE
779         rts
780
781 @TOAST: pla                  ;Remove old return address
782         pla
783         jmp     EXIT         ;Restore interrupts, etc.
784
785 ; ------------------------------------------------------------------------
786 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
787 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
788 ; Contrary to most other functions, the graphics kernel will sort and clip
789 ; the coordinates before calling the driver, so on entry the following
790 ; conditions are valid:
791 ;       X1 <= X2
792 ;       Y1 <= Y2
793 ;       (X1 >= 0) && (X1 < XRES)
794 ;       (X2 >= 0) && (X2 < XRES)
795 ;       (Y1 >= 0) && (Y1 < YRES)
796 ;       (Y2 >= 0) && (Y2 < YRES)
797 ;
798 ; Must set an error code: NO
799 ;
800
801 ; Note: This function needs optimization. It's just a cheap translation of
802 ; the original C wrapper and could be written much smaller (besides that,
803 ; calling LINE is not a good idea either).
804
805 BAR:    lda     Y2
806         sta     Y2SAVE
807         lda     Y2+1
808         sta     Y2SAVE+1
809
810         lda     X2
811         sta     X2SAVE
812         lda     X2+1
813         sta     X2SAVE+1
814
815         lda     Y1
816         sta     Y1SAVE
817         lda     Y1+1
818         sta     Y1SAVE+1
819
820         lda     X1
821         sta     X1SAVE
822         lda     X1+1
823         sta     X1SAVE+1
824
825 @L1:    lda     Y1
826         sta     Y2
827         lda     Y1+1
828         sta     Y2+1
829         jsr     LINE
830
831         lda     Y1SAVE
832         cmp     Y2SAVE
833         bne     @L2
834         lda     Y1SAVE
835         cmp     Y2SAVE
836         beq     @L4
837
838 @L2:    inc     Y1SAVE
839         bne     @L3
840         inc     Y1SAVE+1
841
842 @L3:    lda     Y1SAVE
843         sta     Y1
844         lda     Y1SAVE+1
845         sta     Y1+1
846
847         lda     X1SAVE
848         sta     X1
849         lda     X1SAVE+1
850         sta     X1+1
851
852         lda     X2SAVE
853         sta     X2
854         lda     X2SAVE+1
855         sta     X2+1
856         jmp     @L1
857
858 @L4:    rts
859
860
861 ; ------------------------------------------------------------------------
862 ; CIRCLE: Draw a circle around the center X1/Y1 (= ptr1/ptr2) with the
863 ; radius in tmp1 and the current drawing color.
864 ;
865 ; Must set an error code: NO
866 ;
867
868 CIRCLE: lda     RADIUS
869         sta     CURY
870         bne     @L1
871         jmp     SETPIXEL        ; Plot as a point
872
873 @L1:    clc
874         adc     Y1
875         sta     Y1
876         bcc     @L2
877         inc     Y1+1
878 @L2:    jsr     CALC            ; Compute XC, YC+R
879
880         lda     ROW
881         sta     BROW
882         lda     COL
883         sta     LCOL
884         sta     RCOL
885
886         sty     Y2              ; Y AND 07
887         lda     BITCHUNK,X
888         sta     CHUNK1          ; Forwards chunk
889         sta     OLDCH1
890         lsr
891         eor     #$FF
892         sta     CHUNK2          ; Backwards chunk
893         sta     OLDCH2
894         lda     POINT
895         sta     TEMP2           ; TEMP2 = forwards high pointer
896         sta     X2              ; X2 = backwards high pointer
897         lda     POINT+1
898         sta     TEMP2+1
899         sta     X2+1
900
901 ; Next compute CY-R
902
903         lda     Y1
904         sec
905         sbc     RADIUS
906         bcs     @C3
907         dec     Y1+1
908         sec
909 @C3:    sbc     RADIUS
910         bcs     @C4
911         dec     Y1+1
912 @C4:    sta     Y1
913
914         jsr     CALC            ; Compute new coords
915         sty     Y1
916         lda     POINT
917         sta     X1              ; X1 will be the backwards
918         lda     POINT+1         ; low-pointer
919         sta     X1+1            ; POINT will be forwards
920         lda     ROW
921         sta     TROW
922
923         sei                     ; Get underneath ROM
924         lda     #$34
925         sta     $01
926
927         lda     RADIUS
928         lsr                     ; A=r/2
929         ldx     #00
930         stx     CURX            ; y=0
931
932 ; Main loop
933
934 @LOOP:  inc     CURX            ; x=x+1
935
936         lsr     CHUNK1          ; Right chunk
937         bne     @CONT1
938         jsr     UPCHUNK1        ; Update if we move past a column
939 @CONT1: asl     CHUNK2
940         bne     @CONT2
941         jsr     UPCHUNK2
942 @CONT2: sec
943         sbc     CURX            ; a=a-x
944         bcs     @LOOP
945
946         adc     CURY         ;if a<0 then a=a+y; y=y-1
947         tax
948         jsr     PCHUNK1
949         jsr     PCHUNK2
950         lda     CHUNK1
951         sta     OLDCH1
952         lda     CHUNK2
953         sta     OLDCH2
954         txa
955
956         dec     CURY         ;(y=y-1)
957
958         dec     Y2           ;Decrement y-offest for upper
959         bpl     @CONT3       ;points
960         jsr     DECYOFF
961 @CONT3: ldy     Y1
962         iny
963         sty     Y1
964         cpy     #8
965         bcc     @CONT4
966         jsr     INCYOFF
967 @CONT4: ldy     CURX
968         cpy     CURY         ;if y<=x then punt
969         bcc     @LOOP        ;Now draw the other half
970 ;
971 ; Draw the other half of the circle by exactly reversing
972 ; the above!
973 ;
974 NEXTHALF:
975         lsr     OLDCH1       ;Only plot a bit at a time
976         asl     OLDCH2
977         lda     RADIUS       ;A=-R/2-1
978         lsr
979         eor     #$FF
980 @LOOP:
981         tax
982         jsr     PCHUNK1      ;Plot points
983         jsr     PCHUNK2
984         txa
985         dec     Y2           ;Y2=bottom
986         bpl     @CONT1
987         jsr     DECYOFF
988 @CONT1: inc     Y1
989         ldy     Y1
990         cpy     #8
991         bcc     @CONT2
992         jsr     INCYOFF
993 @CONT2: ldx     CURY
994         beq     @DONE
995         clc
996         adc     CURY         ;a=a+y
997         dec     CURY         ;y=y-1
998         bcc     @LOOP
999
1000         inc     CURX
1001         sbc     CURX         ;if a<0 then x=x+1; a=a+x
1002         lsr     CHUNK1
1003         bne     @CONT3
1004         tax
1005         jsr     UPCH1        ;Upchunk, but no plot
1006 @CONT3: lsr     OLDCH1       ;Only the bits...
1007         asl     CHUNK2       ;Fix chunks
1008         bne     @CONT4
1009         tax
1010         jsr     UPCH2
1011 @CONT4: asl     OLDCH2
1012         bcs     @LOOP
1013 @DONE:
1014 CIRCEXIT:                    ;Restore interrupts
1015         lda     #$37
1016         sta     $01
1017         cli
1018         rts
1019 ;
1020 ; Decrement lower pointers
1021 ;
1022 DECYOFF:
1023         tay
1024         lda     #7
1025         sta     Y2
1026
1027         lda     X2           ;If we pass through zero, then
1028         sec
1029         sbc     #<320        ;subtract 320
1030         sta     X2
1031         lda     X2+1
1032         sbc     #>320
1033         sta     X2+1
1034         lda     TEMP2
1035         sec
1036         sbc     #<320
1037         sta     TEMP2
1038         lda     TEMP2+1
1039         sbc     #>320
1040         sta     TEMP2+1
1041
1042         tya
1043         dec     BROW
1044         bmi     EXIT2
1045         rts
1046 EXIT2:  pla                  ;Grab return address
1047         pla
1048         jmp     CIRCEXIT     ;Restore interrupts, etc.
1049
1050 ; Increment upper pointers
1051 INCYOFF:
1052         tay
1053         lda     #00
1054         sta     Y1
1055         lda     X1
1056         clc
1057         adc     #<320
1058         sta     X1
1059         lda     X1+1
1060         adc     #>320
1061         sta     X1+1
1062         lda     POINT
1063         clc
1064         adc     #<320
1065         sta     POINT
1066         lda     POINT+1
1067         adc     #>320
1068         sta     POINT+1
1069 @ISKIP: inc     TROW
1070         bmi     @DONE
1071         lda     TROW
1072         cmp     #25
1073         bcs     EXIT2
1074 @DONE:  tya
1075         rts
1076
1077 ;
1078 ; UPCHUNK1 -- Update right-moving chunk pointers
1079 ;             Due to passing through a column
1080 ;
1081 UPCHUNK1:
1082         tax
1083         jsr     PCHUNK1
1084 UPCH1:  lda     #$FF         ;Alternative entry point
1085         sta     CHUNK1
1086         sta     OLDCH1
1087         lda     TEMP2
1088         clc
1089         adc     #8
1090         sta     TEMP2
1091         bcc     @CONT
1092         inc     TEMP2+1
1093         clc
1094 @CONT:  lda     POINT
1095         adc     #8
1096         sta     POINT
1097         bcc     @DONE
1098         inc     POINT+1
1099 @DONE:  txa
1100         inc     RCOL
1101         rts
1102
1103 ;
1104 ; UPCHUNK2 -- Update left-moving chunk pointers
1105 ;
1106 UPCHUNK2:
1107         tax
1108         jsr     PCHUNK2
1109 UPCH2:  lda     #$FF
1110         sta     CHUNK2
1111         sta     OLDCH2
1112         lda     X2
1113         sec
1114         sbc     #8
1115         sta     X2
1116         bcs     @CONT
1117         dec     X2+1
1118         sec
1119 @CONT:  lda     X1
1120         sbc     #8
1121         sta     X1
1122         bcs     @DONE
1123         dec     X1+1
1124 @DONE:  txa
1125         dec     LCOL
1126         rts
1127 ;
1128 ; Plot right-moving chunk pairs for circle routine
1129 ;
1130 PCHUNK1:
1131
1132         lda     RCOL         ;Make sure we're in range
1133         cmp     #40
1134         bcs     @SKIP2
1135         lda     CHUNK1       ;Otherwise plot
1136         eor     OLDCH1
1137         sta     TEMP
1138         lda     TROW         ;Check for underflow
1139         bmi     @SKIP
1140         ldy     Y1
1141         lda     (POINT),y
1142         eor     BITMASK
1143         and     TEMP
1144         eor     (POINT),y
1145         sta     (POINT),y
1146
1147 @SKIP:  lda     BROW         ;If CY+Y >= 200...
1148         cmp     #25
1149         bcs     @SKIP2
1150         ldy     Y2
1151         lda     (TEMP2),y
1152         eor     BITMASK
1153         and     TEMP
1154         eor     (TEMP2),y
1155         sta     (TEMP2),y
1156 @SKIP2: rts
1157
1158 ;
1159 ; Plot left-moving chunk pairs for circle routine
1160 ;
1161
1162 PCHUNK2:
1163         lda     LCOL         ;Range check in X
1164         cmp     #40
1165         bcs     EXIT3
1166         lda     CHUNK2       ;Otherwise plot
1167         eor     OLDCH2
1168         sta     TEMP
1169         lda     TROW         ;Check for underflow
1170         bmi     @SKIP
1171         ldy     Y1
1172         lda     (X1),y
1173         eor     BITMASK
1174         and     TEMP
1175         eor     (X1),y
1176         sta     (X1),y
1177
1178 @SKIP:  lda     BROW         ;If CY+Y >= 200...
1179         cmp     #25
1180         bcs     EXIT3
1181         ldy     Y2
1182         lda     (X2),y
1183         eor     BITMASK
1184         and     TEMP
1185         eor     (X2),y
1186         sta     (X2),y
1187 EXIT3:  rts
1188
1189 ; ------------------------------------------------------------------------
1190 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
1191 ; direction is passend in X/Y, the text direction is passed in A.
1192 ;
1193 ; Must set an error code: NO
1194 ;
1195
1196 TEXTSTYLE:
1197         stx     TEXTMAGX
1198         sty     TEXTMAGY
1199         sta     TEXTDIR
1200         rts
1201
1202
1203 ; ------------------------------------------------------------------------
1204 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
1205 ; current text style. The text to output is given as a zero terminated
1206 ; string with address in ptr3.
1207 ;
1208 ; Must set an error code: NO
1209 ;
1210
1211 OUTTEXT:
1212         rts
1213
1214 ; ------------------------------------------------------------------------
1215 ; Calculate all variables to plot the pixel at X1/Y1. If the point is out
1216 ; of range, a carry is returned and INRANGE is set to a value !0 zero. If
1217 ; the coordinates are valid, INRANGE is zero and the carry clear.
1218
1219 CALC:   lda     Y1
1220         sta     ROW
1221         and     #7
1222         tay
1223         lda     Y1+1
1224         lsr                     ; Neg is possible
1225         ror     ROW
1226         lsr
1227         ror     ROW
1228         lsr
1229         ror     ROW
1230
1231         lda     #00
1232         sta     POINT
1233         lda     ROW
1234         cmp     #$80
1235         ror
1236         ror     POINT
1237         cmp     #$80
1238         ror
1239         ror     POINT           ; row*64
1240         adc     ROW             ; +row*256
1241         clc
1242         adc     #>VBASE         ; +bitmap base
1243         sta     POINT+1
1244
1245         lda     X1
1246         tax
1247         sta     COL
1248         lda     X1+1
1249         lsr
1250         ror     COL
1251         lsr
1252         ror     COL
1253         lsr
1254         ror     COL
1255
1256         txa
1257         and     #$F8
1258         clc
1259         adc     POINT           ; +(X AND #$F8)
1260         sta     POINT
1261         lda     X1+1
1262         adc     POINT+1
1263         sta     POINT+1
1264         txa
1265         and     #7
1266         tax
1267
1268         lda     ROW
1269         cmp     #25
1270         bcs     @L9
1271         lda     COL
1272         cmp     #40
1273         bcs     @L9
1274         lda     #00
1275 @L9:    sta     INRANGE
1276         rts
1277
1278