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