+;
+; Generic Atari graphics driver
+;
+
+; ******************************************************************************
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; Header. Includes jump table and constants.
+ ;
+ ; ----------------------------------------------------------------------
+
+.segment "JUMPTABLE"
+
+; Header
+
+ .byte $74, $67, $69 ; "tgi"
+ .byte TGI_API_VERSION ; TGI API version number
+ .word x_res ; X resolution
+ .word y_res ; Y resolution
+ .byte colors ; Number of drawing colors
+ .byte pages ; Number of screens available
+ .byte 8 ; System font X size
+ .byte 8 ; System font Y size
+ .word aspect ; Aspect ratio
+
+; Function table
+
+ .addr INSTALL
+ .addr UNINSTALL
+ .addr INIT
+ .addr DONE
+ .addr GETERROR
+ .addr CONTROL
+ .addr CLEAR
+ .addr SETVIEWPAGE
+ .addr SETDRAWPAGE
+ .addr SETCOLOR
+ .addr SETPALETTE
+ .addr GETPALETTE
+ .addr GETDEFPALETTE
+ .addr SETPIXEL
+ .addr GETPIXEL
+ .addr LINE
+ .addr BAR
+ .addr TEXTSTYLE
+ .addr OUTTEXT
+ .addr 0 ; IRQ entry is unused
+
+; ******************************************************************************
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; Parameters
+ ;
+ ; ----------------------------------------------------------------------
+
+ x1 := ptr1
+ y1 := ptr2
+ x2 := ptr3
+ y2 := ptr4
+ radius := tmp1
+
+; ******************************************************************************
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; Global variables
+ ;
+ ; ----------------------------------------------------------------------
+
+ sptr := regsave + 2
+
+.bss
+ error:
+ .res 1 ; Error code
+ .if grmode = 9 || grmode = 11
+ palette = default_palette
+ .else
+ palette:
+ .res colors ; The current palette
+ .endif
+ mask:
+ .res 1 ; Current pixel mask
+ griocb:
+ .res 1 ; IOCB channel number for graphics
+
+.if pages = 2
+ p0scr:
+ .res 1 ; High byte of screen address for screen page 0
+ p0dls:
+ .res 1 ; High byte of display list address for screen page 0
+ ; Page 1's addresses are 8K higher
+.endif
+
+.data
+ mag_x:
+ .byte 1 ; Horizontal text scaling factor
+ mag_y:
+ .byte 1 ; Vertical text scaling factor
+ mag_x8:
+ .word 8 ; Horizontal text scaling factor * 8
+ mag_y8:
+ .word 8 ; Vertical text scaling factor * 8
+ text_dir:
+ .byte 0 ; Text direction,
+
+.code
+
+; ******************************************************************************
+
+.macro put_pixel
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; Put a pixel at (sptr),y using x as the bit mask offset
+ ;
+ ; ----------------------------------------------------------------------
+
+ lda (sptr),y
+ eor mask
+ and mask_table,x
+ eor (sptr),y
+ sta (sptr),y
+.endmacro
+
+; ******************************************************************************
+
+.rodata
+screen_device:
+ .byte "S:",$9B ; Device code for screen
+screen_device_length := * - screen_device
+
+.code
+
+.proc INIT
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; INIT: Switch to graphics mode
+ ;
+ ; ----------------------------------------------------------------------
+
+
+.code
+ ; Initialize drawing color
+ ldx #$FF
+ stx mask
+
+ ; Find a free IOCB
+ clc
+ lda #$70
+search: tax
+ ldy ICHID,x
+ cpy #$FF
+ beq found
+ sbc #$10
+ bcs search
+
+ ; No free IOCB
+ lda #TGI_ERR_NO_IOCB
+ sta error
+ rts
+
+found: ; Check if enough RAM is available
+ lda #0
+ sub #<mem_needed
+ tay
+ lda RAMTOP
+ sbc #>mem_needed
+ cmp APPMHI + 1
+ bcc nomem
+ bne switch
+ cpy APPMHI
+ bcs switch
+
+ ; No memory
+nomem: lda #TGI_ERR_NO_MEM
+ sta error
+ rts
+
+ ; Switch into graphics mode
+switch: lda #OPEN
+ sta ICCOM,x
+ lda #OPNIN | OPNOT
+ sta ICAX1,x
+ lda #grmode
+ sta ICAX2,x
+ lda #<screen_device
+ sta ICBAL,x
+ lda #>screen_device
+ sta ICBAH,x
+ lda #<screen_device_length
+ sta ICBLL,x
+ lda #>screen_device_length
+ sta ICBLH,x
+ jsr CIOV
+
+ .if pages = 2
+ ; Reserve 8K of high memory
+ lda RAMTOP
+ sub #32
+ sta RAMTOP
+ ; Close and reopen graphics
+ lda #CLOSE
+ sta ICCOM,x
+ jsr CIOV
+ ; Reopen graphics
+ lda #OPEN
+ sta ICCOM,x
+ lda #OPNIN | OPNOT
+ sta ICAX1,x
+ lda #grmode
+ sta ICAX2,x
+ lda #<screen_device
+ sta ICBAL,x
+ lda #>screen_device
+ sta ICBAH,x
+ lda #<screen_device_length
+ sta ICBLL,x
+ lda #>screen_device_length
+ sta ICBLH,x
+ jsr CIOV
+ ; Save screen poniters
+ lda SAVMSC + 1
+ sta p0scr
+ lda SDLSTH
+ sta p0dls
+ .endif
+
+ stx griocb
+ ; Reset the error code and return
+ lda #TGI_ERR_OK
+ sta error
+ rts
+.endproc
+
+; ******************************************************************************
+
+.proc DONE
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; DONE: Switch back to text mode
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ .if pages = 2
+ ; Free 8K of high memory
+ lda RAMTOP
+ add #32
+ sta RAMTOP
+ .endif
+
+ ; Clear griocb
+ lda #$FF
+ ldx griocb
+ sta griocb
+
+ ; Close the S: device
+ lda #CLOSE
+ sta ICCOM,x
+ jsr CIOV
+
+ ; Reopen it in Graphics 0
+ lda #OPEN
+ sta ICCOM,x
+ lda #OPNIN | OPNOT
+ sta ICAX1,x
+ lda #0
+ sta ICAX2,x
+ lda #<screen_device
+ sta ICBAL,x
+ lda #>screen_device
+ sta ICBAH,x
+ lda #<screen_device_length
+ sta ICBLL,x
+ lda #>screen_device_length
+ sta ICBLH,x
+ jsr CIOV
+
+ ; Now close it again; we don't need it anymore
+ lda #CLOSE
+ sta ICCOM,x
+ jmp CIOV
+.endproc
+
+; ******************************************************************************
+
+.proc GETERROR
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; GETERROR: Return the error code in A and clear it
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ ldx #TGI_ERR_OK
+ lda error
+ stx error
+ rts
+.endproc
+
+; ******************************************************************************
+
+.proc CLEAR
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; CLEAR: Clear the screen
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ ; Load the screen address in sptr
+ lda SAVMSC
+ sta sptr
+ lda SAVMSC + 1
+ sta sptr + 1
+
+ ; Fill with zero
+ lda #0
+ tay
+
+ ; Clear full pages if any
+ .if >(scrsize) > 0
+ ldx #>(scrsize)
+loop1: sta (sptr),y
+ iny
+ bne loop1
+ inc sptr + 1
+ dex
+ bne loop1
+ .endif
+
+ ; Clear the rest, if any
+ .if <(scrsize) > 0
+loop2: sta (sptr),y
+ iny
+ cpy #<(scrsize)
+ bne loop2
+ .endif
+
+ rts
+.endproc
+
+; ******************************************************************************
+
+.proc GETPALETTE
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; GETPALETTE: Return the current palette in A/X
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ lda #<palette
+ ldx #>palette
+ rts
+.endproc
+
+; ******************************************************************************
+
+.proc GETDEFPALETTE
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; GETDEFPALETTE: Return the default palette in A/X
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ lda #<default_palette
+ ldx #>default_palette
+ rts
+.endproc
+
+; ******************************************************************************
+
+.proc SETCOLOR
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; SETCOLOR: Set the drawing color (in A)
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ tax
+ .if grmode = 9
+ ; Map colors like this: 0 -> 0, 1 -> 15, 2 -> 1, 3 -> 2 etc.
+ beq @cont
+ cpx #1
+ bne @map
+ ldx #16
+@map: dex
+@cont: .endif
+ lda masks,x
+ sta mask
+ rts
+.endproc
+
+; ******************************************************************************
+
+.proc CALC
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; CALC: Calculate the screen address
+ ; in
+ ; x1 (ptr1) x coordinate
+ ; y1 (ptr2) y coordinate
+ ; out
+ ; sptr + y screen address
+ ; x bit mask index
+ ;
+ ; ----------------------------------------------------------------------
+
+.bss
+ temp: .res 1
+.code
+ ; calculate line offset
+ lda y1 + 1
+ sta temp
+ lda y1
+
+ .if x_res / ppb = 40
+ .define yrep 3
+ .elseif x_res / ppb = 20
+ .define yrep 2
+ .elseif x_res / ppb = 10
+ .define yrep 1
+ .endif
+
+ .repeat yrep
+ asl a
+ rol temp
+ .endrepeat
+ sta sptr
+ ldx temp
+ stx sptr + 1
+ .repeat 2
+ asl a
+ rol temp
+ .endrepeat
+ add sptr
+ sta sptr
+ lda temp
+ adc sptr + 1
+ sta sptr + 1
+
+ ; calculate bit mask offset
+ lda x1
+ and #ppb - 1
+ tax
+
+ ; calculate row offset
+ lda x1 + 1
+ sta temp
+ lda x1
+
+ .if ppb = 8
+ .define xrep 3
+ .elseif ppb = 4
+ .define xrep 2
+ .elseif ppb = 2
+ .define xrep 1
+ .endif
+ .repeat xrep
+ lsr temp
+ ror a
+ .endrepeat
+ tay
+
+ ; sptr += SAVMSC
+ lda SAVMSC
+ add sptr
+ sta sptr
+ lda SAVMSC + 1
+ adc sptr + 1
+ sta sptr + 1
+
+ ; We're done!
+ rts
+.endproc
+
+; ******************************************************************************
+
+.proc SETPIXEL
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; Draw one pixel at x1, y1
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ jsr CALC
+ put_pixel
+ rts
+.endproc
+
+; ******************************************************************************
+
+.proc GETPIXEL
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; GETPIXEL: Read the color value of a pixel and return it in A/X
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ jsr CALC
+ lda (sptr),y
+ and mask_table,x
+ .if ppb = 8
+ beq zero
+ lda #1
+zero: ldx #0
+ rts
+ .elseif ppb = 4
+loop: cpx #3
+ beq cont
+ lsr a
+ lsr a
+ inx
+ bne loop
+cont: and #$03
+ rts
+ .elseif ppb = 2
+ dex
+ bne shift
+ and #$0F
+ jmp exit
+shift: ldx #0
+ lsr a
+ lsr a
+ lsr a
+ lsr a
+
+ ; Mode 9 mapping
+exit: .if grmode = 9
+ ; Map colors like this: 0 -> 0, 15 -> 1, 2 -> 3, 3 -> 4 etc.
+ beq @cont
+ cmp #15
+ bne @map
+ lda #0
+@map: add #1
+@cont: .endif
+
+ ; Mode 10 mapping
+ .if grmode = 10
+ ; Map out of range colors like this:
+ ; 9 -> 8
+ ; 10 -> 8
+ ; 11 -> 8
+ ; 12 -> 0
+ ; 13 -> 1
+ ; 14 -> 2
+ ; 15 -> 3
+ cmp #8
+ bcs @cont
+ sub #12
+ bcs @cont
+ lda #8
+@cont: .endif
+
+ ; Done!
+ rts
+ .endif
+.endproc
+
+; ******************************************************************************
+
+.proc LINE
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; LINE: Draw a line from x1,y1 to x2,y2
+ ;
+ ; ----------------------------------------------------------------------
+
+; locals
+
+ dx := sreg
+ dy := y1
+ dx2 := x2
+ dy2 := y2
+ iy := tmp1
+ err := tmp3
+
+.code
+ ; dx = x2 - x1
+ lda x2
+ sub x1
+ sta dx
+ lda x2 + 1
+ sbc x1 + 1
+ sta dx + 1
+ ; if dx is positive, no problem
+ bcs dx_positive
+
+ ; if dx is negative, swap x1,y1 with x2,y2
+ lda x1 ; x1 <-> x2, low byte
+ ldx x2
+ sta x2
+ stx x1
+ lda x1 + 1 ; x1 <-> x2, high byte
+ ldx x2 + 1
+ sta x2 + 1
+ stx x1 + 1
+ lda y1 ; y1 <-> y2, low byte
+ ldx y2
+ sta y2
+ stx y1
+ lda y1 + 1 ; y1 <-> y2, high byte
+ ldx y2 + 1
+ sta y2 + 1
+ stx y1 + 1
+ ; Calculate again
+ jmp LINE
+
+dx_positive:
+ ; Calculate coords
+ jsr CALC
+
+ ; dy = y2 - y1
+ lda y2
+ sub y1
+ sta dy
+ lda y2 + 1
+ sbc y1 + 1
+ sta dy + 1
+
+ ; if dy is negative
+ bcs dy_positive
+ ; dy = -dy
+ lda #0
+ sub dy
+ sta dy
+ lda #0
+ sbc dy + 1
+ sta dy + 1
+ ; iy = -row_size
+ lda #<(65536 - x_res / ppb)
+ sta iy
+ lda #>(65536 - x_res / ppb)
+ sta iy + 1
+ bne skip_iy_1 ; always
+
+dy_positive:
+ ; iy = row_size
+ lda #<(x_res / ppb)
+ sta iy
+ lda #>(x_res / ppb)
+ sta iy + 1
+skip_iy_1:
+
+ ; dx2 = dx * 2
+ lda dx
+ asl a
+ sta dx2
+ lda dx + 1
+ rol a
+ sta dx2 + 1
+
+ ; dy2 = dy * 2
+ lda dy
+ asl a
+ sta dy2
+ lda dy + 1
+ rol a
+ sta dy2 + 1
+
+ ; if dx >= dy
+ lda dx
+ cmp dy
+ lda dx + 1
+ sbc dy + 1
+ bcc dy_major
+
+ ; dx is the major axis
+
+ ; err = dy2 - dx
+ lda dy2
+ sub dx
+ sta err
+ lda dy2 + 1
+ sbc dx + 1
+ sta err + 1
+
+ .scope
+loop: ; main loop
+ put_pixel
+ ; if err >= 0
+ lda err + 1
+ bmi err_neg
+ ; err -= dx2
+ lda err
+ sub dx2
+ sta err
+ lda err + 1
+ sbc dx2 + 1
+ sta err + 1
+ ; move_vertical (iy)
+ lda sptr
+ add iy
+ sta sptr
+ lda sptr + 1
+ adc iy + 1
+ sta sptr + 1
+err_neg:
+ ; err += dy2
+ lda err
+ add dy2
+ sta err
+ lda err + 1
+ adc dy2 + 1
+ sta err + 1
+ ; move_right
+ inx
+ cpx #ppb
+ bne end_move
+ ldx #0
+ iny
+ bne end_move
+ inc sptr + 1
+end_move:
+ ; loop while dx-- >= 0
+ lda dx
+ ora dx + 1
+ beq exit
+ dec dx
+ lda dx
+ cmp #$FF
+ bne loop
+ dec dx + 1
+ jmp loop
+exit: rts
+ .endscope
+
+dy_major:
+ ; dy is the major axis
+
+ ; err = dx2 - dy;
+ lda dx2
+ sub dy
+ sta err
+ lda dx2 + 1
+ sbc dy + 1
+ sta err + 1
+
+ .scope
+loop: ; main loop
+ put_pixel
+ ; if err >= 0
+ lda err + 1
+ bmi end_move
+ ; err -= dy2
+ lda err
+ sub dy2
+ sta err
+ lda err + 1
+ sbc dy2 + 1
+ sta err + 1
+ ; move_right
+ inx
+ cpx #ppb
+ bne end_move
+ ldx #0
+ iny
+ bne end_move
+ inc sptr + 1
+end_move:
+ ; err += dx2
+ lda err
+ add dx2
+ sta err
+ lda err + 1
+ adc dx2 + 1
+ sta err + 1
+ ; move_vertical(iy)
+ lda sptr
+ add iy
+ sta sptr
+ lda sptr + 1
+ adc iy + 1
+ sta sptr + 1
+ ; loop while dy-- >= 0
+ lda dy
+ ora dy + 1
+ beq exit
+ dec dy
+ lda dy
+ cmp #$FF
+ bne loop
+ dec dy + 1
+ jmp loop
+exit: rts
+ .endscope
+.endproc
+
+; ******************************************************************************
+
+.proc clipped_bar
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; Clip and draw bar
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ lda y1 + 1
+ bne off
+ lda y1
+ cmp #y_res
+ bcs off
+
+ lda x1 + 1
+ .if >(x_res - 1) > 0
+ cmp #>x_res
+ bcc check2
+ .endif
+ bne off
+ lda x1
+ cmp #<x_res
+ bcc check2
+off: rts
+
+check2: lda y2 + 1
+ bne off
+ lda y2
+ cmp #y_res
+ bcs off
+
+ lda x2 + 1
+ .if >(x_res - 1) > 0
+ cmp #>x_res
+ bcc BAR
+ .endif
+ bne off
+ lda x2
+ cmp #<x_res
+ bcs off
+.endproc
+
+; ******************************************************************************
+
+.proc BAR
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; BAR: Draw a filled rectangle with the corners at x1,y1,x2,y2
+ ;
+ ; ----------------------------------------------------------------------
+
+; locals
+ lmem := sreg
+.bss
+ lmask: .res 1
+ rmask: .res 1
+ dy: .res 1
+ dx: .res 1
+ fmask: .res 1
+.code
+ ; dy = y2 - y1 + 1
+ lda y2
+ sub y1
+ sta dy
+ inc dy
+ ; Calculate upper left corner
+ jsr CALC
+ ; Save the values
+ tya
+ add sptr
+ sta lmem
+ lda sptr + 1
+ adc #0
+ sta lmem + 1
+ lda bar_table,x
+ sta lmask
+ ; Calculate upper right corner
+ lda x2
+ sta x1
+ .if >(x_res - 1) > 0
+ lda x2 + 1
+ sta x1 + 1
+ .endif
+ jsr CALC
+ ; Save the values
+ tya
+ add sptr
+ sta sptr
+ bcc skips
+ inc sptr + 1
+skips: inx
+ lda bar_table,x
+ eor #$FF
+ sta rmask
+ ; Calculate memory difference between x1 and x2
+ lda sptr
+ sub lmem
+ sta dx
+loop: ; Main loop
+ ldy #0
+ ldx dx
+ beq same
+ ; Left
+ lda (lmem),y
+ eor mask
+ and lmask
+ eor (lmem),y
+ sta (lmem),y
+ iny
+ ; Between
+ lda mask
+ jmp next
+btwn: sta (lmem),y
+ iny
+next: dex
+ bne btwn
+ ; Right
+ lda (lmem),y
+ eor mask
+ and rmask
+ eor (lmem),y
+ sta (lmem),y
+ jmp cont
+same: ; Same byte
+ lda lmask
+ and rmask
+ sta fmask
+ lda (lmem),y
+ eor mask
+ and fmask
+ eor (lmem),y
+ sta (lmem),y
+cont: ; Go to next row
+ lda lmem
+ add #<(x_res / ppb)
+ sta lmem
+ bcc skipm
+ inc lmem + 1
+skipm: ; Loop while --dy > 0
+ dec dy
+ bne loop
+
+ rts
+
+.endproc
+
+; ******************************************************************************
+
+.proc TEXTSTYLE
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; TEXTSTYLE: Set text style. Scale factors in X and Y and direction in A
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ stx mag_x
+ sty mag_y
+ ; Save text direction in bit 8 so that we can use BIT instruction later
+ lsr a
+ ror a
+ sta text_dir
+ ; Save 8 * scaling factors
+ lda #0
+ sta mag_x8 + 1
+ sta mag_y8 + 1
+ ; Save 8 * mag_x
+ txa
+ .repeat 3
+ asl a
+ rol mag_x8 + 1
+ .endrepeat
+ sta mag_x8
+ ; Save 8 * mag_y
+ tya
+ .repeat 3
+ asl a
+ rol mag_y8 + 1
+ .endrepeat
+ sta mag_y8
+ ; Done!
+ rts
+.endproc
+
+; ******************************************************************************
+
+.proc OUTTEXT
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; OUTTEXT: Draw text at x1, y1. String is in ptr3
+ ;
+ ; ----------------------------------------------------------------------
+
+; locals
+ string := tmp1
+ cols := tmp3
+ pixels := tmp4
+ font := regsave
+.rodata
+ ataint: .byte 64,0,32,96
+.bss
+ rows: .res 1
+ .if >(x_res - 1) > 0
+ oldx1: .res 2
+ oldx2: .res 2
+ .else
+ oldx1: .res 1
+ oldx2: .res 1
+ .endif
+ oldy1: .res 1
+ oldy2: .res 1
+ inv: .res 1
+.code
+ ; Don't draw zero sized characters
+ lda mag_x
+ beq @exit
+ lda mag_y
+ bne @cont
+@exit: rts
+@cont: ; Save string address, ptr3 is needed by BAR
+ lda ptr3
+ sta string
+ lda ptr3 + 1
+ sta string + 1
+
+ bit text_dir
+ bmi vert
+
+ ; Calculate x2
+ lda mag_x
+ sub #1
+ add x1
+ sta x2
+ .if >(x_res - 1) > 0
+ lda x1 + 1
+ adc #0
+ sta x2 + 1
+ .else
+ lda #0
+ sta x2 + 1
+ .endif
+
+ ; Calculate y2 and adjust y1
+ dec y1
+ lda y1
+ sta y2
+ sub mag_y
+ add #1
+ sta y1
+ lda #0
+ sta y2 + 1
+
+ jmp while
+
+ ; Calculate for vertical text
+vert: lda x1
+ sub #1
+ sta x2
+ lda x1 + 1
+ sbc #0
+ sta x2 + 1
+ lda x1
+ sub mag_y
+ sta x1
+ lda x1 + 1
+ sbc #0
+ sta x1 + 1
+
+ lda mag_x
+ sub #1
+ add y1
+ sta y2
+ lda #0
+ sta y2 + 1
+ beq while ; Always
+
+ ; Main loop
+loop: inc string
+ bne skiph
+ inc string + 1
+skiph: ; Save coords
+ jsr save_text_y
+ ; Draw one character
+ jsr outchar
+ ; Restore coords
+ jsr restore_text_y
+ ; End of loop
+while: ldy #0
+ lda (string),y
+ bne loop ; Check for null character
+ rts
+
+ ; --------------------
+ ; Output one character
+outchar:
+ ; Convert to ANTIC code
+ tay
+ rol a
+ rol a
+ rol a
+ rol a
+ and #3
+ tax
+ tya
+ and #$9f
+ ora ataint,x
+ ; Save and clear inverse video bit
+ sta inv
+ and #$7F
+ ; Calculate font data address
+ sta font
+ lda #0
+ sta font + 1
+ .repeat 3
+ asl font
+ rol a
+ .endrepeat
+ adc CHBAS
+ sta font + 1
+ ; Save old coords
+ bit text_dir
+ bpl @hor
+ lda y1
+ sta oldy1
+ lda y2
+ sta oldy2
+ jmp @cont
+@hor: lda x1
+ sta oldx1
+ lda x2
+ sta oldx2
+ .if >(x_res - 1) > 0
+ lda x1 + 1
+ sta oldx1 + 1
+ lda x2 + 1
+ sta oldx2 + 1
+ .endif
+ ; Get glyph pixels
+@cont: ldy #7
+ ; Put one row of the glyph
+putrow: sty rows
+ lda (font),y
+ bit inv
+ bpl noinv
+ eor #$FF
+noinv: sta pixels
+ lda #7
+ sta cols
+ ; Put one column of the row
+putcol: asl pixels
+ bcc next_col
+ lda x1
+ pha
+ lda x1 + 1
+ pha
+ jsr clipped_bar
+ pla
+ sta x1 + 1
+ pla
+ sta x1
+next_col:
+ ; Go to next column
+ jsr inc_x
+ dec cols
+ bpl putcol
+next_row:
+ ; Go to next row
+ jsr dec_y
+ ; Restore old values
+ bit text_dir
+ bpl @hor
+ lda oldy1
+ sta y1
+ lda oldy2
+ sta y2
+ jmp @cont
+@hor: lda oldx1
+ sta x1
+ lda oldx2
+ sta x2
+ .if >(x_res - 1) > 0
+ lda oldx1 + 1
+ sta x1 + 1
+ lda oldx2 + 1
+ sta x2 + 1
+ .endif
+ ; Next row
+@cont: ldy rows
+ dey
+ bpl putrow
+
+ ; We're done!
+ rts
+
+
+; -------------------------
+inc_x: ; increase x coords
+ bit text_dir
+ bmi @vert
+
+ lda mag_x
+ add x1
+ sta x1
+ bcc @1
+ inc x1 + 1
+@1: lda mag_x
+ add x2
+ sta x2
+ bcc @2
+ inc x2 + 1
+@2: rts
+
+@vert: lda y1
+ sub mag_x
+ sta y1
+ lda y2
+ sub mag_x
+ sta y2
+ rts
+
+; -------------------------
+dec_y: ; decrease y coords
+ bit text_dir
+ bmi @vert
+
+ lda y1
+ sub mag_y
+ sta y1
+ bcs @1
+ dec y1 + 1
+@1: lda y2
+ sub mag_y
+ sta y2
+ bcs @2
+ dec y2 + 1
+@2: rts
+
+@vert: lda x1
+ sub mag_y
+ sta x1
+ bcs @3
+ dec x1 + 1
+@3: lda x2
+ sub mag_y
+ sta x2
+ bcs @4
+ dec x2 + 1
+@4: rts
+
+; -------------------------
+save_text_y: ; Save text's height coords
+ bit text_dir
+ bmi @vert
+ ldx y1
+ stx oldy1
+ ldx y2
+ stx oldy2
+ rts
+@vert: ldx x1
+ stx oldx1
+ ldx x2
+ stx oldx2
+ .if >(x_res - 1) > 0
+ ldx x1 + 1
+ stx oldx1 + 1
+ ldx x2 + 1
+ stx oldx2 + 1
+ .endif
+ rts
+
+; -------------------------
+restore_text_y: ; Position to next char
+ bit text_dir
+ bmi @vert
+
+ ldx oldy1
+ stx y1
+ ldx oldy2
+ stx y2
+ ldx #0
+ stx y1 + 1
+ stx y2 + 1
+
+ lda mag_x8
+ add x1
+ sta x1
+ lda mag_x8 + 1
+ adc x1 + 1
+ sta x1 + 1
+ lda mag_x8
+ add x2
+ sta x2
+ lda mag_x8 + 1
+ adc x2 + 1
+ sta x2 + 1
+
+ rts
+
+@vert: ldx oldx1
+ stx x1
+ ldx oldx2
+ stx x2
+ .if >(x_res - 1) > 0
+ ldx oldx1 + 1
+ stx x1 + 1
+ ldx oldx2 + 1
+ stx x2 + 1
+ .endif
+
+ lda y1
+ sub mag_x8
+ sta y1
+ lda y1 +1
+ sbc mag_x8 + 1
+ sta y1 + 1
+ lda y2
+ sub mag_x8
+ sta y2
+ lda y2 +1
+ sbc mag_x8 + 1
+ sta y2 + 1
+
+ rts
+
+.endproc
+
+.if pages = 2
+; ******************************************************************************
+
+.proc SETVIEWPAGE
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; SETVIEWPAGE, page in A
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ tax
+ beq cont
+ lda #32
+
+cont: add p0dls
+ cmp SDLSTH
+ beq done ; We're already in the desired page
+
+ ldx RTCLOK + 2
+ sta SDLSTH
+
+ ; Wait until next VBLANK
+wait: cpx RTCLOK + 2
+ beq wait
+
+ ; Done
+done: rts
+.endproc
+
+; ******************************************************************************
+
+.proc SETDRAWPAGE
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; SETDRAWPAGE, page in A
+ ;
+ ; ----------------------------------------------------------------------
+
+.code
+ tax
+ beq @cont
+ lda #32
+@cont: add p0scr
+ sta SAVMSC + 1
+ rts
+.endproc
+.endif
+
+; ******************************************************************************
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; Unimplemented functions that require an error code
+ ;
+ ; ----------------------------------------------------------------------
+
+CONTROL:
+ lda #TGI_ERR_INV_FUNC
+ sta error
+ ; fall through
+
+; ******************************************************************************
+
+ ; ----------------------------------------------------------------------
+ ;
+ ; Unimplemented functions that don't require an error code
+ ;
+ ; ----------------------------------------------------------------------
+
+INSTALL:
+UNINSTALL:
+.if pages = 1
+SETVIEWPAGE:
+SETDRAWPAGE:
+.endif
+ rts