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