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