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