]> git.sur5r.net Git - cc65/blob - libsrc/lynx/lynx-160-102-16.s
a27496cbcf516489a0137879983da5c22b9ef3bc
[cc65] / libsrc / lynx / lynx-160-102-16.s
1 ;
2 ; Graphics driver for the 160x102x16 mode on the Lynx.
3 ;
4 ; All the drawing functions are simply done by sprites as the sprite
5 ; engine is the only way to do fast graphics on a Lynx.
6 ;
7 ; So the code is not really based on any algorithms done by somebody.
8 ; I have looked at other routines in the cc65 libs to see what kind of
9 ; entry points we need. And I have looked at the old cc65 libs by
10 ; Bastian Schick to see how things worked in the past.
11 ;
12 ; This code is written by Karri Kaksonen, 2004 for the cc65 compiler.
13 ;
14
15         .include        "zeropage.inc"
16         .include        "extzp.inc"
17
18         .include        "tgi-kernel.inc"
19         .include        "tgi-mode.inc"
20         .include        "tgi-error.inc"
21
22         .include        "lynx.inc"
23
24         .macpack        generic
25
26 ; ------------------------------------------------------------------------
27 ; Header. Includes jump table and constants.
28
29 .segment        "JUMPTABLE"
30
31 ; First part of the header is a structure that has a magic and defines the
32 ; capabilities of the driver
33
34         .byte   $74, $67, $69           ; "tgi"
35         .byte   TGI_API_VERSION         ; TGI API version number
36         .word   160                     ; X resolution
37         .word   102                     ; Y resolution
38         .byte   16                      ; Number of drawing colors
39         .byte   2                       ; Number of screens available
40         .byte   8                       ; System font X size
41         .byte   8                       ; System font Y size
42         .res    4, $00                  ; Reserved for future extensions
43
44 ; Next comes the jump table. Currently all entries must be valid and may point
45 ; to an RTS for test versions (function not implemented). A future version may
46 ; allow for emulation: In this case the vector will be zero. Emulation means
47 ; that the graphics kernel will emulate the function by using lower level
48 ; primitives - for example ploting a line by using calls to SETPIXEL.
49
50         .addr   INSTALL
51         .addr   UNINSTALL
52         .addr   INIT
53         .addr   DONE
54         .addr   GETERROR
55         .addr   CONTROL
56         .addr   CLEAR
57         .addr   SETVIEWPAGE
58         .addr   SETDRAWPAGE
59         .addr   SETCOLOR
60         .addr   SETPALETTE
61         .addr   GETPALETTE
62         .addr   GETDEFPALETTE
63         .addr   SETPIXEL
64         .addr   GETPIXEL
65         .addr   LINE
66         .addr   BAR
67         .addr   CIRCLE
68         .addr   TEXTSTYLE
69         .addr   OUTTEXT
70         .addr   IRQ
71
72
73 ; ------------------------------------------------------------------------
74 ; Data.
75
76 ; Variables mapped to the zero page segment variables. Some of these are
77 ; used for passing parameters to the driver.
78
79 X1              := ptr1
80 Y1              := ptr2
81 X2              := ptr3
82 Y2              := ptr4
83
84 STRPTR          := ptr3
85 FONTOFF         := ptr4
86 STROFF          := tmp3
87 STRLEN          := tmp4
88
89 ; Absolute variables used in the code
90
91 .bss
92
93 ERROR:          .res    1       ; Error code
94
95 DRAWINDEX:      .res    1       ; Pen to use for drawing
96 VIEWPAGEL:      .res    1
97 VIEWPAGEH:      .res    1
98 DRAWPAGEL:      .res    1
99 DRAWPAGEH:      .res    1
100
101 ; Text output stuff
102 TEXTMAGX:       .res    1
103 TEXTMAGY:       .res    1
104 TEXTDIR:        .res    1
105 BGINDEX:        .res    1       ; Pen to use for text background
106
107 ; Double buffer IRQ stuff
108 DRAWPAGE:       .res    1
109 SWAPREQUEST:    .res    1
110
111 text_bitmap:    .res    8*(1+20+1)+1
112 ; 8 rows with (one offset-byte plus 20 character bytes plus one fill-byte) plus one 0-offset-byte
113
114 ; Constants and tables
115
116 .rodata
117
118 DEFPALETTE:     .byte   >$000
119                 .byte   >$007
120                 .byte   >$070
121                 .byte   >$700
122                 .byte   >$077
123                 .byte   >$770
124                 .byte   >$707
125                 .byte   >$777
126                 .byte   >$333
127                 .byte   >$00F
128                 .byte   >$0F0
129                 .byte   >$F00
130                 .byte   >$0FF
131                 .byte   >$FF0
132                 .byte   >$F0F
133                 .byte   >$FFF
134                 .byte   <$000
135                 .byte   <$007
136                 .byte   <$070
137                 .byte   <$700
138                 .byte   <$077
139                 .byte   <$770
140                 .byte   <$707
141                 .byte   <$777
142                 .byte   <$333
143                 .byte   <$00F
144                 .byte   <$0F0
145                 .byte   <$F00
146                 .byte   <$0FF
147                 .byte   <$FF0
148                 .byte   <$F0F
149                 .byte   <$FFF
150
151 PALETTESIZE     = * - DEFPALETTE
152
153 .code
154
155 ; ------------------------------------------------------------------------
156 ; INSTALL routine. Is called after the driver is loaded into memory. May
157 ; initialize anything that has to be done just once. Is probably empty
158 ; most of the time.
159 ;
160 ; Must set an error code: NO
161 ;
162
163 INSTALL:
164         lda     #1
165         sta     TEXTMAGX
166         sta     TEXTMAGY
167         stz     BGINDEX
168         stz     DRAWPAGE
169         stz     SWAPREQUEST
170         rts
171
172
173 ; ------------------------------------------------------------------------
174 ; UNINSTALL routine. Is called before the driver is removed from memory. May
175 ; clean up anything done by INSTALL but is probably empty most of the time.
176 ;
177 ; Must set an error code: NO
178 ;
179
180 UNINSTALL:
181         rts
182
183
184 ; ------------------------------------------------------------------------
185 ; INIT: Changes an already installed device from text mode to graphics
186 ; mode.
187 ; Note that INIT/DONE may be called multiple times while the driver
188 ; is loaded, while INSTALL is only called once, so any code that is needed
189 ; to initializes variables and so on must go here. Setting palette and
190 ; clearing the screen is not needed because this is called by the graphics
191 ; kernel later.
192 ; The graphics kernel will never call INIT when a graphics mode is already
193 ; active, so there is no need to protect against that.
194 ;
195 ; Must set an error code: YES
196 ;
197
198 INIT:
199 ; Done, reset the error code
200         lda     #TGI_ERR_OK
201         sta     ERROR
202         rts
203
204 ; ------------------------------------------------------------------------
205 ; DONE: Will be called to switch the graphics device back into text mode.
206 ; The graphics kernel will never call DONE when no graphics mode is active,
207 ; so there is no need to protect against that.
208 ;
209 ; Must set an error code: NO
210 ;
211
212 DONE:
213         rts
214
215 ; ------------------------------------------------------------------------
216 ; GETERROR: Return the error code in A and clear it.
217
218 GETERROR:
219         ldx     #TGI_ERR_OK
220         lda     ERROR
221         stx     ERROR
222         rts
223
224 ; ------------------------------------------------------------------------
225 ; CONTROL: Platform/driver specific entry point.
226 ;
227 ; Must set an error code: YES
228 ;
229 ; The TGI lacks a way to draw sprites. As that functionality is vital to
230 ; Lynx games we borrow this CONTROL function to implement the still
231 ; missing tgi_draw_sprite funtion. To use this in your C-program
232 ; do a #define tgi_draw_sprite(spr) tgi_ioctl(0, spr)
233 ;
234 ; To do a flip-screen call tgi_ioctl(1, 0)
235 ;
236 ; To set the background index for text outputs call tgi_ioctl(2, bgindex)
237 ;
238 ; To set the frame rate for the display hardware call tgi_ioctl(3, rate)
239 ;
240 ; To check if the drawing engine is busy with the previous swap you can
241 ; call tgi_ioctl(4, 0). It returns 0 if idle and 1 if busy
242 ;
243 ; To update displays you can call tgi_ioctl(4, 1) it will wait for the
244 ; next VBL interrupt and swap draw and view buffers.
245
246 CONTROL:
247         pha                     ; Almost all control routines succeed
248         lda     #TGI_ERR_OK
249         sta     ERROR
250         pla
251
252         cmp     #4
253         bne     ControlFramerate
254
255         lda     ptr1            ; Swap request
256         bne     @L0
257         lda     SWAPREQUEST
258         rts
259 @L0:    sta     SWAPREQUEST
260         rts
261
262 ControlFramerate:
263         cmp     #3
264         bne     ControlTextBG
265
266         lda     ptr1
267         cmp     #75             ; Set framerate
268         beq     rate75
269         cmp     #60
270         beq     rate60
271         cmp     #50
272         beq     rate50
273         lda     #TGI_ERR_INV_ARG
274         sta     ERROR
275         rts
276 rate50: lda     #$bd            ; 50 Hz
277         ldx     #$31
278         bra     setRate
279 rate60: lda     #$9e            ; 60 Hz
280         ldx     #$29
281         bra     setRate
282 rate75: lda     #$7e            ; 75 Hz
283         ldx     #$20
284 setRate:
285         sta     HTIMBKUP
286         stx     PBKUP
287         rts
288
289 ControlTextBG:
290         cmp     #2
291         bne     ControlFlipScreen
292
293         lda     ptr1            ; Set text background color
294         sta     BGINDEX
295         rts
296
297 ControlFlipScreen:
298         cmp     #1
299         bne     ControlDrawSprite
300
301         lda     __sprsys        ; Flip screen
302         eor     #8
303         sta     __sprsys
304         sta     SPRSYS
305         lda     __viddma
306         eor     #2
307         sta     __viddma
308         sta     DISPCTL
309         ldy     VIEWPAGEL
310         ldx     VIEWPAGEH
311         and     #2
312         beq     NotFlipped
313         clc
314         tya
315         adc     #<8159
316         tay
317         txa
318         adc     #>8159
319         tax
320 NotFlipped:
321         sty     DISPADRL
322         stx     DISPADRH
323         rts
324
325 ControlDrawSprite:
326         lda     ptr1            ; Get the sprite address
327         ldx     ptr1+1
328
329 draw_sprite:                    ; Draw it in render buffer
330         sta     SCBNEXTL
331         stx     SCBNEXTH
332         lda     DRAWPAGEL
333         ldx     DRAWPAGEH
334         sta     VIDBASL
335         stx     VIDBASH
336         lda     #1
337         sta     SPRGO
338         stz     SDONEACK
339 @L0:    stz     CPUSLEEP
340         lda     SPRSYS
341         lsr
342         bcs     @L0
343         stz     SDONEACK
344         lda     #TGI_ERR_OK
345         sta     ERROR
346         rts
347
348 ; ------------------------------------------------------------------------
349 ; CLEAR: Clears the screen.
350 ;
351 ; Must set an error code: NO
352 ;
353
354 .rodata
355 pixel_bitmap:
356         .byte   3,%10000100,%00000000, $0       ; A pixel bitmap
357 cls_sprite:
358         .byte   %00000001                       ; A pixel sprite
359         .byte   %00010000
360         .byte   %00100000
361         .addr   0,pixel_bitmap
362         .word   0
363         .word   0
364         .word   $a000                           ; 160
365         .word   $6600                           ; 102
366         .byte   $00
367
368 .code
369 CLEAR:  lda     #<cls_sprite
370         ldx     #>cls_sprite
371         bra     draw_sprite
372
373 ; ------------------------------------------------------------------------
374 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
375 ; The page number is already checked to be valid by the graphics kernel.
376 ;
377 ; Must set an error code: NO (will only be called if page ok)
378 ;
379 ; It is a good idea to call this function during the vertical blanking
380 ; period. If you call it in the middle of the screen update then half of
381 ; the drawn frame will be from the old buffer and the other half is
382 ; from the new buffer. This is usually noticed by the user.
383
384 SETVIEWPAGE:
385         cmp     #1
386         beq     @L1             ; page == maxpages-1
387         ldy     #<$de20         ; page 0
388         ldx     #>$de20
389         bra     @L2
390 @L1:
391         ldy     #<$be40         ; page 1
392         ldx     #>$be40
393 @L2:
394         sty     VIEWPAGEL       ; Save viewpage for getpixel
395         stx     VIEWPAGEH
396
397         lda     __viddma        ; Process flipped displays
398         and     #2
399         beq     @L3
400         clc
401         tya
402         adc     #<8159
403         tay
404         txa
405         adc     #>8159
406         tax
407 @L3:
408         sty     DISPADRL        ; $FD94
409         stx     DISPADRH        ; $FD95
410         rts
411
412 ; ------------------------------------------------------------------------
413 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
414 ; The page number is already checked to be valid by the graphics kernel.
415 ;
416 ; Must set an error code: NO (will only be called if page ok)
417 ;
418
419 SETDRAWPAGE:
420         cmp     #1
421         beq     @L1                 ; page == maxpages-1
422         lda     #<$de20             ; page 0
423         ldx     #>$de20
424         bra     @L2
425 @L1:
426         lda     #<$be40             ; page 1
427         ldx     #>$be40
428 @L2:
429         sta     DRAWPAGEL
430         stx     DRAWPAGEH
431         rts
432
433 ; ------------------------------------------------------------------------
434 ; IRQ: VBL interrupt handler
435 ;
436
437 TIMER0_INTERRUPT = $01
438 TIMER1_INTERRUPT = $02
439 TIMER2_INTERRUPT = $04
440 TIMER3_INTERRUPT = $08
441 TIMER4_INTERRUPT = $10
442 TIMER5_INTERRUPT = $20
443 TIMER6_INTERRUPT = $40
444 TIMER7_INTERRUPT = $80
445
446 HBL_INTERRUPT = TIMER0_INTERRUPT
447 VBL_INTERRUPT = TIMER2_INTERRUPT
448 SERIAL_INTERRUPT = TIMER4_INTERRUPT
449
450 IRQ:
451         lda     INTSET          ; Poll all pending interrupts
452         and     #VBL_INTERRUPT
453         beq     IRQEND          ; Exit if not a VBL interrupt
454
455         lda     SWAPREQUEST
456         beq     @L0
457         lda     DRAWPAGE
458         jsr     SETVIEWPAGE
459         lda     DRAWPAGE
460         eor     #1
461         sta     DRAWPAGE
462         jsr     SETDRAWPAGE
463         stz     SWAPREQUEST
464 @L0:
465 IRQEND:
466         clc
467         rts
468
469 ; ------------------------------------------------------------------------
470 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
471 ; to be in a valid range (0..maxcolor-1).
472 ;
473 ; Must set an error code: NO (will only be called if color ok)
474 ;
475
476 SETCOLOR:
477         sta     DRAWINDEX
478         rts
479
480 ; ------------------------------------------------------------------------
481 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
482 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
483 ; are not supported
484 ;
485 ; Must set an error code: YES
486 ;
487
488 SETPALETTE:
489         ldy     #31
490 @L1:    lda     (ptr1),y
491         sta     GCOLMAP,y   ; $FDA0
492         dey
493         bpl     @L1
494
495 ; Done, reset the error code
496
497         lda     #TGI_ERR_OK
498         sta     ERROR
499         rts
500
501 ; ------------------------------------------------------------------------
502 ; GETPALETTE: Return the current palette in A/X. Even drivers that cannot
503 ; set the palette should return the default palette here, so there's no
504 ; way for this function to fail.
505 ;
506 ; Must set an error code: NO
507 ;
508
509 GETPALETTE:
510         lda     #<GCOLMAP       ; $FDA0
511         ldx     #>GCOLMAP
512         rts
513
514 ; ------------------------------------------------------------------------
515 ; GETDEFPALETTE: Return the default palette for the driver in A/X. All
516 ; drivers should return something reasonable here, even drivers that don't
517 ; support palettes, otherwise the caller has no way to determine the colors
518 ; of the (not changeable) palette.
519 ;
520 ; Must set an error code: NO (all drivers must have a default palette)
521 ;
522
523 GETDEFPALETTE:
524         lda     #<DEFPALETTE
525         ldx     #>DEFPALETTE
526         rts
527
528 ; ------------------------------------------------------------------------
529 ; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
530 ; color. The coordinates passed to this function are never outside the
531 ; visible screen area, so there is no need for clipping inside this function.
532 ;
533 ; Must set an error code: NO
534 ;
535
536 .data
537 pixel_sprite:
538         .byte   %00000001                       ; A pixel sprite
539         .byte   %00010000
540         .byte   %00100000
541         .addr   0,pixel_bitmap
542 pix_x:  .word   0
543 pix_y:  .word   0
544         .word   $100
545         .word   $100
546 pix_c:  .byte   $00
547
548 .code
549 SETPIXEL:
550         lda     X1
551         sta     pix_x
552         lda     Y1
553         sta     pix_y
554         lda     DRAWINDEX
555         sta     pix_c
556         lda     #<pixel_sprite
557         ldx     #>pixel_sprite
558         jmp     draw_sprite
559
560 ; ------------------------------------------------------------------------
561 ; GETPIXEL: Read the color value of a pixel and return it in A/X. The
562 ; coordinates passed to this function are never outside the visible screen
563 ; area, so there is no need for clipping inside this function.
564
565
566 GETPIXEL:
567         lda     Y1
568         sta     MATHD   ; Hardware multiply
569         stz     MATHC
570         lda     #80
571         sta     MATHB
572         stz     MATHA
573         lda     X1
574         lsr     A
575         php
576         tay
577
578         clc
579         lda     VIEWPAGEL
580         adc     MATHH
581         sta     ptr1
582         lda     VIEWPAGEH
583         adc     MATHG
584         sta     ptr1+1
585
586         ldx     #0
587         lda     #15
588         sta     MAPCTL
589         lda     (ptr1),y
590         tay
591         lda     #$0c
592         sta     MAPCTL
593         tya
594         plp
595         bcc     @L1
596         and     #$f
597         rts
598
599 @L1:    lsr     A
600         lsr     A
601         lsr     A
602         lsr     A
603         rts
604
605 ; ------------------------------------------------------------------------
606 ; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
607 ; X2/Y2 = ptr3/ptr4 using the current drawing color.
608 ;
609 ; Must set an error code: NO
610 ;
611
612 .data
613 line_sprite:
614         .byte   0               ; Will be replaced by the code
615         .byte   %00110000
616         .byte   %00100000
617         .word   0,pixel_bitmap
618 line_x:
619         .word    0
620 line_y:
621         .word    0
622 line_sx:
623         .word    $100
624 line_sy:
625         .word    $100
626         .word    0
627 line_tilt:
628         .word    0
629 line_c:
630         .byte    $e
631
632 .code
633 LINE:
634         lda     DRAWINDEX
635         sta     line_c
636         stz     line_sx
637         stz     line_sy
638
639         sec
640         lda     X2
641         sbc     X1
642         lda     X2+1
643         sbc     X1+1
644         bpl     @L1
645         lda     X1
646         ldx     X2
647         sta     X2
648         stx     X1
649         lda     X1+1
650         ldx     X2+1
651         sta     X2+1
652         stx     X1+1
653         lda     Y1
654         ldx     Y2
655         sta     Y2
656         stx     Y1
657         lda     Y1+1
658         ldx     Y2+1
659         sta     Y2+1
660         stx     Y1+1
661 @L1:
662         lda     #%00000000      ; Not flipped
663         sta     line_sprite
664
665         sec
666         lda     Y2
667         sbc     Y1
668         sta     Y2
669         lda     Y2+1
670         sbc     Y1+1
671         sta     Y2+1
672         bpl     @L2
673         sec
674         lda     #0
675         sbc     Y2
676         sta     Y2
677         lda     #0
678         sbc     Y2+1
679         sta     Y2+1
680         lda     #%00010000      ; Vertical flip
681         sta     line_sprite
682 @L2:
683         lda     X1
684         sta     line_x
685         lda     X1+1
686         sta     line_x+1
687         lda     Y1
688         sta     line_y
689         lda     Y1+1
690         sta     line_y+1
691
692         lda     Y2
693         ina
694         sta     line_sy+1
695         sta     MATHP           ; hardware divide
696         stz     MATHN
697
698         stz     MATHH
699         stz     MATHG
700         sec
701         lda     X2
702         sbc     X1
703         ina
704         sta     MATHF
705         stz     MATHE
706 @L3:
707         lda     SPRSYS
708         bmi     @L3             ; wait for math done (bit 7 of sprsys)
709         lda     MATHC
710         sta     line_tilt
711         lda     MATHB
712         sta     line_tilt+1
713         bne     @L4
714         lda     #1
715         sta     line_sx+1
716         bra     @L6
717 @L4:
718         bit     line_tilt
719         bpl     @L5
720         ina
721 @L5:
722         sta     line_sx+1
723 @L6:
724         lda     #<line_sprite
725         ldx     #>line_sprite
726         jmp     draw_sprite
727
728 ; ------------------------------------------------------------------------
729 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
730 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
731 ; Contrary to most other functions, the graphics kernel will sort and clip
732 ; the coordinates before calling the driver, so on entry the following
733 ; conditions are valid:
734 ;       X1 <= X2
735 ;       Y1 <= Y2
736 ;       (X1 >= 0) && (X1 < XRES)
737 ;       (X2 >= 0) && (X2 < XRES)
738 ;       (Y1 >= 0) && (Y1 < YRES)
739 ;       (Y2 >= 0) && (Y2 < YRES)
740 ;
741 ; Must set an error code: NO
742 ;
743
744 .data
745 bar_sprite:
746         .byte   %00000001                       ; A pixel sprite
747         .byte   %00010000
748         .byte   %00100000
749         .addr   0,pixel_bitmap
750 bar_x:  .word   0
751 bar_y:  .word   0
752 bar_sx: .word   $0100
753 bar_sy: .word   $0100
754 bar_c:  .byte   $00
755
756 .code
757 BAR:    lda     X1
758         sta     bar_x
759         lda     Y1
760         sta     bar_y
761         lda     X2
762         sec
763         sbc     X1
764         ina
765         sta     bar_sx+1
766         lda     Y2
767         sec
768         sbc     Y1
769         ina
770         sta     bar_sy+1
771         lda     DRAWINDEX
772         sta     bar_c
773         lda     #<bar_sprite
774         ldx     #>bar_sprite
775         jmp     draw_sprite
776
777 ; ------------------------------------------------------------------------
778 ; CIRCLE: Draw a circle around the center X1/Y1 (= ptr1/ptr2) with the
779 ; radius in tmp1 and the current drawing color.
780 ;
781 ; Must set an error code: NO
782 ;
783 ; There is no sensible way of drawing a circle on a Lynx. As I would
784 ; have to use line elements to do the circle I rather do it in C than
785 ; create it here in the driver.
786
787 ; To do a circle please add this to your C program
788
789 ;int sintbl[9] = {
790 ;       0,     //  0    degrees
791 ;       3196,  // 11.25 degrees
792 ;       6270,  // 22.5  degrees
793 ;       9102,  // 33.75 degrees
794 ;       11585, // 45    degrees
795 ;       13623, // 56.25 degrees
796 ;       15137, // 67.5  degrees
797 ;       16069, // 78.75 degrees
798 ;       16384  // 90    degrees
799 ;};
800
801 ;int sin(char d)
802 ;{
803 ;    char neg;
804 ;    d = d & 31;
805 ;    neg = d > 16;
806 ;    d = d & 15;
807 ;    if (d > 8)
808 ;        d = 16 - d;
809 ;    if (neg)
810 ;       return -sintbl[d];
811 ;    else
812 ;       return sintbl[d];
813 ;}
814
815 ;void tgi_Circle(int x0, int y0, unsigned char r)
816 ;{
817 ;       char i;
818 ;       int x1, y1, x2, y2;
819 ;
820 ;       x1 = ((long)sin(0) * r + 8192) / 16384 + x0;
821 ;       y1 = ((long)sin(8) * r + 8192) / 16384 + y0;
822 ;       for (i = 1; i <= 32; i++) {
823 ;               x2 = ((long)sin(i) * r + 8192) / 16384 + x0;
824 ;               y2 = ((long)sin(i+8) * r + 8192) / 16384 + y0;
825 ;               tgi_line(x1, y1, x2, y2);
826 ;               x1 = x2;
827 ;               y1 = y2;
828 ;       }
829 ;}
830
831 ;#define tgi_circle tgi_Circle
832
833 CIRCLE:
834         rts
835
836 ; ------------------------------------------------------------------------
837 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
838 ; direction is passend in X/Y, the text direction is passed in A.
839 ;
840 ; Must set an error code: NO
841 ;
842
843 TEXTSTYLE:
844         stx     TEXTMAGX
845         sty     TEXTMAGY
846         sta     TEXTDIR
847         rts
848
849 ; ------------------------------------------------------------------------
850 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
851 ; current text style. The text to output is given as a zero terminated
852 ; string with address in ptr3.
853 ;
854 ; Must set an error code: NO
855 ;
856
857 OUTTEXT:
858         lda     TEXTMAGX        ; Scale sprite
859         sta     text_sx+1
860         lda     TEXTMAGY
861         sta     text_sy+1
862
863         stz     text_sprite     ; Set normal sprite
864         lda     BGINDEX
865         bne     @L1
866         lda     #4
867         sta     text_sprite     ; Set opaque sprite
868 @L1:
869         lda     DRAWINDEX       ; Set color
870         asl
871         asl
872         asl
873         asl
874         ora     BGINDEX
875         sta     text_c
876
877         lda     X1              ; Set start position
878         sta     text_x
879         lda     X1+1
880         sta     text_x+1
881         lda     Y1
882         sta     text_y
883         lda     Y1+1
884         sta     text_y+1
885
886         ldy     #-1             ; Calculate string length
887 @L2:
888         iny
889         lda     (STRPTR),y
890         bne     @L2
891         cpy     #20
892         bmi     @L3
893         ldy     #20
894 @L3:
895         sty     STRLEN
896         bne     @L4
897         rts                     ; Zero length string
898 @L4:
899         iny                     ; Prepare text_bitmap
900         iny
901         sty     STROFF
902
903         ldy     #8-1            ; 8 pixel lines per character
904         ldx     #0
905         clc
906 @L5:
907         lda     STROFF
908         sta     text_bitmap,x
909         txa
910         adc     STROFF
911         tax
912         lda     #$ff
913         sta     text_bitmap-1,x
914         dey
915         bpl     @L5
916         stz     text_bitmap,x
917
918         stz     tmp2
919         iny
920 @L6:
921         lda     (STRPTR),y
922         sty     tmp1
923
924         sec                     ; (ch-' ') * 8
925         sbc     #32
926         stz     FONTOFF
927         stz     FONTOFF+1
928         asl
929         asl
930         rol     FONTOFF+1
931         asl
932         rol     FONTOFF+1
933         clc                     ; Choose font
934         adc     #<font
935         sta     FONTOFF
936         lda     FONTOFF+1
937         adc     #>font
938         sta     FONTOFF+1
939
940 ; and now copy the 8 bytes of that char
941
942         ldx     tmp2
943         inx
944         stx     tmp2
945
946 ; draw char from top to bottom, reading char-data from offset 8-1 to offset 0
947         ldy     #8-1
948 @L7:
949         lda     (FONTOFF),y         ; *chptr
950         sta     text_bitmap,x    ;textbuf[y*(1+len+1)+1+x]
951
952         txa
953         adc     STROFF
954         tax
955
956         dey
957         bpl     @L7
958
959         ; goto next char
960         ldy     tmp1
961         iny
962         dec     STRLEN
963         bne     @L6
964
965         lda     #<text_sprite
966         ldx     #>text_sprite
967         jmp     draw_sprite
968
969 .data
970 text_sprite:
971         .byte $00,$90,$20
972         .addr 0, text_bitmap
973 text_x:
974         .word 0
975 text_y:
976         .word 0
977 text_sx:
978         .word $100
979 text_sy:
980         .word $100
981 text_c:
982         .byte 0
983
984 .rodata
985 ; The Font
986 ; 96 characters from ASCII 32 to 127
987 ; 8 pixels wide, 8 pixels high
988 ; bit value 0 = foreground, bit value 1 = background / transparent
989 font:
990 ; VERSAIL
991         .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF  ;32
992         .byte $FF, $E7, $FF, $FF, $E7, $E7, $E7, $E7  ;33
993         .byte $FF, $FF, $FF, $FF, $FF, $99, $99, $99  ;34
994         .byte $FF, $99, $99, $00, $99, $00, $99, $99  ;35
995         .byte $FF, $E7, $83, $F9, $C3, $9F, $C1, $E7  ;36
996         .byte $FF, $B9, $99, $CF, $E7, $F3, $99, $9D  ;37
997         .byte $FF, $C0, $99, $98, $C7, $C3, $99, $C3  ;38
998         .byte $FF, $FF, $FF, $FF, $FF, $E7, $F3, $F9  ;39
999         .byte $FF, $F3, $E7, $CF, $CF, $CF, $E7, $F3  ;40
1000         .byte $FF, $CF, $E7, $F3, $F3, $F3, $E7, $CF  ;41
1001         .byte $FF, $FF, $99, $C3, $00, $C3, $99, $FF  ;42
1002         .byte $FF, $FF, $E7, $E7, $81, $E7, $E7, $FF  ;43
1003         .byte $CF, $E7, $E7, $FF, $FF, $FF, $FF, $FF  ;44
1004         .byte $FF, $FF, $FF, $FF, $81, $FF, $FF, $FF  ;45
1005         .byte $FF, $E7, $E7, $FF, $FF, $FF, $FF, $FF  ;46
1006         .byte $FF, $9F, $CF, $E7, $F3, $F9, $FC, $FF  ;47
1007         .byte $FF, $C3, $99, $99, $89, $91, $99, $C3  ;48
1008         .byte $FF, $81, $E7, $E7, $E7, $C7, $E7, $E7  ;49
1009         .byte $FF, $81, $9F, $CF, $F3, $F9, $99, $C3  ;50
1010         .byte $FF, $C3, $99, $F9, $E3, $F9, $99, $C3  ;51
1011         .byte $FF, $F9, $F9, $80, $99, $E1, $F1, $F9  ;52
1012         .byte $FF, $C3, $99, $F9, $F9, $83, $9F, $81  ;53
1013         .byte $FF, $C3, $99, $99, $83, $9F, $99, $C3  ;54
1014         .byte $FF, $E7, $E7, $E7, $E7, $F3, $99, $81  ;55
1015         .byte $FF, $C3, $99, $99, $C3, $99, $99, $C3  ;56
1016         .byte $FF, $C3, $99, $F9, $C1, $99, $99, $C3  ;57
1017         .byte $FF, $FF, $E7, $FF, $FF, $E7, $FF, $FF  ;58
1018         .byte $CF, $E7, $E7, $FF, $FF, $E7, $FF, $FF  ;59
1019         .byte $FF, $F1, $E7, $CF, $9F, $CF, $E7, $F1  ;60
1020         .byte $FF, $FF, $FF, $81, $FF, $81, $FF, $FF  ;61
1021         .byte $FF, $8F, $E7, $F3, $F9, $F3, $E7, $8F  ;62
1022         .byte $FF, $E7, $FF, $E7, $F3, $F9, $99, $C3  ;63
1023
1024
1025         .byte $FF, $C3, $9D, $9F, $91, $91, $99, $C3  ;0
1026         .byte $FF, $99, $99, $99, $81, $99, $C3, $E7  ;1
1027         .byte $FF, $83, $99, $99, $83, $99, $99, $83  ;2
1028         .byte $FF, $C3, $99, $9F, $9F, $9F, $99, $C3  ;3
1029         .byte $FF, $87, $93, $99, $99, $99, $93, $87  ;4
1030         .byte $FF, $81, $9F, $9F, $87, $9F, $9F, $81  ;5
1031         .byte $FF, $9F, $9F, $9F, $87, $9F, $9F, $81  ;6
1032         .byte $FF, $C3, $99, $99, $91, $9F, $99, $C3  ;7
1033         .byte $FF, $99, $99, $99, $81, $99, $99, $99  ;8
1034         .byte $FF, $C3, $E7, $E7, $E7, $E7, $E7, $C3  ;9
1035         .byte $FF, $C7, $93, $F3, $F3, $F3, $F3, $E1  ;10
1036         .byte $FF, $99, $93, $87, $8F, $87, $93, $99  ;11
1037         .byte $FF, $81, $9F, $9F, $9F, $9F, $9F, $9F  ;12
1038         .byte $FF, $9C, $9C, $9C, $94, $80, $88, $9C  ;13
1039         .byte $FF, $99, $99, $91, $81, $81, $89, $99  ;14
1040         .byte $FF, $C3, $99, $99, $99, $99, $99, $C3  ;15
1041         .byte $FF, $9F, $9F, $9F, $83, $99, $99, $83  ;16
1042         .byte $FF, $F1, $C3, $99, $99, $99, $99, $C3  ;17
1043         .byte $FF, $99, $93, $87, $83, $99, $99, $83  ;18
1044         .byte $FF, $C3, $99, $F9, $C3, $9F, $99, $C3  ;19
1045         .byte $FF, $E7, $E7, $E7, $E7, $E7, $E7, $81  ;20
1046         .byte $FF, $C3, $99, $99, $99, $99, $99, $99  ;21
1047         .byte $FF, $E7, $C3, $99, $99, $99, $99, $99  ;22
1048         .byte $FF, $9C, $88, $80, $94, $9C, $9C, $9C  ;23
1049         .byte $FF, $99, $99, $C3, $E7, $C3, $99, $99  ;24
1050         .byte $FF, $E7, $E7, $E7, $C3, $99, $99, $99  ;25
1051         .byte $FF, $81, $9F, $CF, $E7, $F3, $F9, $81  ;26
1052         .byte $FF, $C3, $CF, $CF, $CF, $CF, $CF, $C3  ;27
1053         .byte $FF, $03, $9D, $CF, $83, $CF, $ED, $F3  ;28
1054         .byte $FF, $C3, $F3, $F3, $F3, $F3, $F3, $C3  ;29
1055         .byte $E7, $E7, $E7, $E7, $81, $C3, $E7, $FF  ;30
1056         .byte $FF, $EF, $CF, $80, $80, $CF, $EF, $FF  ;31
1057
1058
1059 ; gemena
1060         .byte $FF, $C3, $9D, $9F, $91, $91, $99, $C3  ;224
1061         .byte $FF, $C1, $99, $C1, $F9, $C3, $FF, $FF  ;225
1062         .byte $FF, $83, $99, $99, $83, $9F, $9F, $FF  ;226
1063         .byte $FF, $C3, $9F, $9F, $9F, $C3, $FF, $FF  ;227
1064         .byte $FF, $C1, $99, $99, $C1, $F9, $F9, $FF  ;228
1065         .byte $FF, $C3, $9F, $81, $99, $C3, $FF, $FF  ;229
1066         .byte $FF, $E7, $E7, $E7, $C1, $E7, $F1, $FF  ;230
1067         .byte $83, $F9, $C1, $99, $99, $C1, $FF, $FF  ;231
1068         .byte $FF, $99, $99, $99, $83, $9F, $9F, $FF  ;232
1069         .byte $FF, $C3, $E7, $E7, $C7, $FF, $E7, $FF  ;233
1070         .byte $C3, $F9, $F9, $F9, $F9, $FF, $F9, $FF  ;234
1071         .byte $FF, $99, $93, $87, $93, $9F, $9F, $FF  ;235
1072         .byte $FF, $C3, $E7, $E7, $E7, $E7, $C7, $FF  ;236
1073         .byte $FF, $9C, $94, $80, $80, $99, $FF, $FF  ;237
1074         .byte $FF, $99, $99, $99, $99, $83, $FF, $FF  ;238
1075         .byte $FF, $C3, $99, $99, $99, $C3, $FF, $FF  ;239
1076         .byte $9F, $9F, $83, $99, $99, $83, $FF, $FF  ;240
1077         .byte $F9, $F9, $C1, $99, $99, $C1, $FF, $FF  ;241
1078         .byte $FF, $9F, $9F, $9F, $99, $83, $FF, $FF  ;242
1079         .byte $FF, $83, $F9, $C3, $9F, $C1, $FF, $FF  ;243
1080         .byte $FF, $F1, $E7, $E7, $E7, $81, $E7, $FF  ;244
1081         .byte $FF, $C1, $99, $99, $99, $99, $FF, $FF  ;245
1082         .byte $FF, $E7, $C3, $99, $99, $99, $FF, $FF  ;246
1083         .byte $FF, $C9, $C1, $80, $94, $9C, $FF, $FF  ;247
1084         .byte $FF, $99, $C3, $E7, $C3, $99, $FF, $FF  ;248
1085         .byte $87, $F3, $C1, $99, $99, $99, $FF, $FF  ;249
1086         .byte $FF, $81, $CF, $E7, $F3, $81, $FF, $FF  ;250
1087         .byte $FF, $C3, $CF, $CF, $CF, $CF, $CF, $C3  ;251
1088         .byte $FF, $03, $9D, $CF, $83, $CF, $ED, $F3  ;252
1089         .byte $FF, $C3, $F3, $F3, $F3, $F3, $F3, $C3  ;253
1090         .byte $E7, $E7, $E7, $E7, $81, $C3, $E7, $FF  ;254
1091         .byte $FF, $EF, $CF, $80, $80, $CF, $EF, $FF  ;255