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