;; Optimised Drawing library
;; By Jon Fuge (jonny@q-continuum.demon.co.uk) based on original file
;; Updates
;;   990223 Michael     Removed mod_col, splitting it up into
;;                      fg_colour, bg_colour, and draw_mode
;; Note: some optimisations are available with unneded PUSH DE/POP DE's

        .include        "global.s"

        .globl  .init_vram
        .globl  .copy_vram

        .globl  .drawing_lcd
        .globl  .bg_colour, .fg_colour, .draw_mode

        .M_SOLID        = 0x00
        .M_OR           = 0x01
        .M_XOR          = 0x02
        .M_AND          = 0x03

        ;;  Format of mod_col
        ;; 7 6 5 4 3 2 1 0
        ;;   mode  fg  bg

        .area   _DRAW_HEADER (ABS)

        .org    0x70
.drawing_bits_tbl::
        .byte   0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01
        .byte   0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80

        .org    .MODE_TABLE+4*.G_MODE
        JP      .gmode

        .module Drawing1

        .area   _DATA

        ;; Fill style
.style:
        .ds     0x01
        ;; Various varibles
.x_s:
        .ds     2
.y_s:
        .ds     2
.delta_x:
        .ds     1
.delta_y:
        .ds     1
.l_inc:
        .ds     1
.l_d:
        .ds     2
.dinc1:
        .ds     2
.dinc2:
        .ds     2
.tx:
        .ds     1
.ty:
        .ds     1

        .area   _HOME

        ;; Enter graphic mode
.gmode::
        DI                      ; Disable interrupts

        PUSH    DE              ; preserve DE

        ;; Turn the screen off
        LDH     A,(.LCDC)
        AND     #LCDCF_ON
        JR      Z,1$

        ;; Turn the screen off
        CALL    .display_off
1$:
        LD      HL,#0x8000+0x10*0x10
        LD      DE,#0x1800-0x18*0x10
        LD      B,#0x00
        CALL    .init_vram      ; Init the charset at 0x8000

        ;; Install interrupt routines
        LD      DE,#.drawing_lcd
        CALL    .add_LCD

        LD      A,#72           ; Set line at which LCD interrupt occurs
        LDH     (.LYC),A

        LD      A,#STATF_LYC
        LDH     (.STAT),A

        LDH     A,(.IE)
        OR      #.LCD_IFLAG     ; Enable LCD interrupt
        LDH     (.IE),A

        ;; (9*20) = 180 tiles are used in the upper part of the screen
        ;; (9*20) = 180 tiles are used in the lower part of the screen
        ;; => We have 24 tiles free
        ;; We keep 16 at 0x8000->0x80FF, and 8 at 0x9780->97FF

        LD      HL,#0x9800
        LD      A,#0x10         ; Keep 16 tiles free
        LD      BC,#12          ; 12 unused columns
        LD      E,#18           ; 18 lines
2$:
        LD      D,#20           ; 20 used columns
3$:
        LD      (HL+),A
        INC     A
        DEC     D
        JR      NZ,3$
        ADD     HL,BC
        DEC     E
        JR      NZ,2$

        ;; Turn the screen on
        LDH     A,(.LCDC)
        OR      #(LCDCF_ON | LCDCF_BG8000 | LCDCF_BGON)
        AND     #~LCDCF_BG9C00  ; BG Bank       = 0x9800
        LDH     (.LCDC),A

        LD      A,#.G_MODE
        LD      (.mode),A

        ;; Setup the default colours and draw modes
        LD      A,#.M_SOLID
        LD      (.draw_mode),A
        LD      A,#0x03         ; Black
        LD      (.fg_colour),A
        LD      A,#0x00         ; White
        LD      (.bg_colour),A

        POP     DE              ; restore DE

        XOR     A
        LDH     (.IF), A

        EI                      ; Enable interrupts

        RET

        ;; Replace tile data at (B,C) with data at DE and store old value at HL
.switch_data::
        PUSH    DE              ; Save src
        PUSH    HL              ; Save dst
        LD      L,B
        SLA     L
        SLA     L
        SLA     L
        LD      H,#0x00
        ADD     HL,HL
        LD      D,H
        LD      E,L

        LD      HL,#.y_table
        SLA     C
        SLA     C
        SLA     C
        LD      B,#0x00
        ADD     HL,BC
        ADD     HL,BC
        LD      A,(HL+)
        LD      H,(HL)
        LD      L,A
        ADD     HL,DE

        POP     DE
        PUSH    HL
        LD      A,H
        OR      L
        JR      Z,1$
        LD      BC,#0x10
        CALL    .copy_vram
1$:
        POP     DE
        POP     HL
        LD      A,D
        OR      E
        JR      Z,2$
        LD      BC,#0x10
        CALL    .copy_vram
2$:
        RET

        ;; Advance the cursor
.adv_gcurs::
        PUSH    HL
        LD      HL,#.tx ; X coordinate
        LD      A,#.MAXCURSPOSX
        CP      (HL)
        JR      Z,1$
        INC     (HL)
        JR      99$
1$:
        LD      (HL),#0x00
        LD      HL,#.ty ; Y coordinate
        LD      A,#.MAXCURSPOSY
        CP      (HL)
        JR      Z,2$
        INC     (HL)
        JR      99$
2$:
        LD      (HL),#0x00
99$:
        POP     HL
        RET

        ;; Draw a circle from (B,C) with radius D
.circle::
        LD      A,B     ;Store center values
        LD      (.x_s),A
        LD      A,C
        LD      (.y_s),A

        XOR     A
        LD      (.x_s+1),A
        LD      A,D
        LD      (.y_s+1),A
        CPL
        LD      L,A
        LD      H,#0xFF
        INC     HL
        LD      BC,#0
        ADD     HL,BC
        LD      A,L
        LD      (.l_d+1),A
        LD      A,H
        LD      (.l_d),A

cloop$:
        LD      A,(.x_s+1)
        LD      B,A
        LD      A,(.y_s+1)
        SUB     B
        RET     C

        LD      A,(.style)
        OR      A
        CALL    Z,.circplot

        LD      A,(.l_d)
        BIT     7,A
        JR      Z,ycirc$

        LD      A,(.style)
        OR      A
        CALL    NZ,.horlin
        LD      A,(.x_s+1)
        INC     A
        LD      (.x_s+1),A
        LD      A,(.l_d)
        LD      B,A
        LD      A,(.l_d+1)
        LD      C,A
        LD      H,#0
        LD      A,(.x_s+1)
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,BC
        LD      BC,#6
        ADD     HL,BC
        LD      A,H
        LD      (.l_d),A
        LD      A,L
        LD      (.l_d+1),A
        JR      cloop$
ycirc$:
        LD      A,(.style)
        OR      A
        CALL    NZ,.verlin
        LD      A,(.x_s+1)
        INC     A
        LD      (.x_s+1),A
        LD      B,#0
        LD      A,(.x_s+1)
        LD      C,A
        LD      H,#0xFF
        LD      A,(.y_s+1)
        CPL
        LD      L,A
        INC     HL
        ADD     HL,BC
        LD      A,(.l_d)
        LD      B,A
        LD      A,(.l_d+1)
        LD      C,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,BC
        LD      BC,#10
        ADD     HL,BC
        LD      A,H
        LD      (.l_d),A
        LD      A,L
        LD      (.l_d+1),A
        LD      A,(.y_s+1)
        DEC     A
        LD      (.y_s+1),A
        JP      cloop$

.horlin::
        LD      A,(.x_s)
        LD      B,A
        LD      A,(.y_s)
        LD      C,A
        LD      A,(.x_s+1)
        LD      D,A
        LD      A,(.y_s+1)
        LD      E,A
        PUSH    BC
        PUSH    DE
        LD      A,B
        SUB     E
        LD      H,A
        LD      A,B
        ADD     E
        LD      B,A
        LD      A,C
        ADD     D
        LD      C,A
        LD      D,H
        LD      E,C
        CALL    .line
        POP     DE
        POP     BC
        LD      A,D
        OR      A
        RET     Z
        PUSH    BC
        PUSH    DE
        LD      A,B
        SUB     E
        LD      H,A
        LD      A,B
        ADD     E
        LD      B,A
        LD      A,C
        SUB     D
        LD      C,A
        LD      D,H
        LD      E,C
        CALL    .line
        POP     DE
        POP     BC
        RET

.verlin::
        LD      A,(.x_s)
        LD      B,A
        LD      A,(.y_s)
        LD      C,A
        LD      A,(.x_s+1)
        LD      D,A
        LD      A,(.y_s+1)
        LD      E,A
        PUSH    BC
        PUSH    DE
        LD      A,B
        SUB     E
        LD      H,A
        LD      A,B
        ADD     E
        LD      B,A
        LD      A,C
        ADD     D
        LD      C,A
        LD      D,H
        LD      E,C
        CALL    .line
        POP     DE
        POP     BC
        PUSH    BC
        PUSH    DE
        LD      A,B
        SUB     E
        LD      H,A
        LD      A,B
        ADD     E
        LD      B,A
        LD      A,C
        SUB     D
        LD      C,A
        LD      D,H
        LD      E,C
        CALL    .line
        POP     DE
        POP     BC
        LD      A,D
        SUB     E
        RET     Z
        PUSH    BC
        PUSH    DE
        LD      A,B
        SUB     D
        LD      H,A
        LD      A,B
        ADD     D
        LD      B,A
        LD      A,C
        SUB     E
        LD      C,A
        LD      D,H
        LD      E,C
        CALL    .line
        POP     DE
        POP     BC
        PUSH    BC
        PUSH    DE
        LD      A,B
        SUB     D
        LD      H,A
        LD      A,B
        ADD     D
        LD      B,A
        LD      A,C
        ADD     E
        LD      C,A
        LD      D,H
        LD      E,C
        CALL    .line
        POP     DE
        POP     BC
        RET

.circplot::
        LD      A,(.x_s)
        LD      B,A
        LD      A,(.y_s)
        LD      C,A
        LD      A,(.x_s+1)
        LD      D,A
        LD      A,(.y_s+1)
        LD      E,A
        PUSH    BC
        PUSH    DE
        LD      A,B
        ADD     D
        LD      B,A
        LD      A,C
        SUB     E
        LD      C,A
        CALL    .plot
        POP     DE
        POP     BC
        PUSH    BC
        PUSH    DE
        LD      A,B
        SUB     E
        LD      B,A
        LD      A,C
        SUB     D
        LD      C,A
        CALL    .plot
        POP     DE
        POP     BC
        PUSH    BC
        PUSH    DE
        LD      A,B
        SUB     D
        LD      B,A
        LD      A,C
        ADD     E
        LD      C,A
        CALL    .plot
        POP     DE
        POP     BC
        PUSH    BC
        PUSH    DE
        LD      A,B
        ADD     E
        LD      B,A
        LD      A,C
        ADD     D
        LD      C,A
        CALL    .plot
        POP     DE
        POP     BC

        LD      A,D
        OR      A
        RET     Z
        SUB     E
        RET     Z

        PUSH    BC
        PUSH    DE
        LD      A,B
        SUB     D
        LD      B,A
        LD      A,C
        SUB     E
        LD      C,A
        CALL    .plot
        POP     DE
        POP     BC
        PUSH    BC
        PUSH    DE
        LD      A,B
        SUB     E
        LD      B,A
        LD      A,C
        ADD     D
        LD      C,A
        CALL    .plot
        POP     DE
        POP     BC
        PUSH    BC
        PUSH    DE
        LD      A,B
        ADD     D
        LD      B,A
        LD      A,C
        ADD     E
        LD      C,A
        CALL    .plot
        POP     DE
        POP     BC
        PUSH    BC
        PUSH    DE
        LD      A,B
        ADD     E
        LD      B,A
        LD      A,C
        SUB     D
        LD      C,A
        CALL    .plot
        POP     DE
        POP     BC
        RET

        ;; Draw a box between (B,C) and (D,E)
.box::
        LD      A,(.x_s)
        LD      B,A
        LD      A,(.x_s+1)
        LD      C,A
        SUB     B
        JR      NC,ychk$
        LD      A,C
        LD      (.x_s),A
        LD      A,B
        LD      (.x_s+1),A
ychk$:
        LD      A,(.y_s)
        LD      B,A
        LD      A,(.y_s+1)
        LD      C,A
        SUB     B
        JR      NC,dbox$
        LD      A,C
        LD      (.y_s),A
        LD      A,B
        LD      (.y_s+1),A
dbox$:
        LD      A,(.x_s)
        LD      B,A
        LD      D,A
        LD      A,(.y_s)
        LD      C,A
        LD      A,(.y_s+1)
        LD      E,A
        CALL    .line
        LD      A,(.x_s+1)
        LD      B,A
        LD      D,A
        LD      A,(.y_s)
        LD      C,A
        LD      A,(.y_s+1)
        LD      E,A
        CALL    .line
        LD      A,(.x_s)
        INC     A
        LD      (.x_s),A
        LD      A,(.x_s+1)
        DEC     A
        LD      (.x_s+1),A
        LD      A,(.x_s)
        LD      B,A
        LD      A,(.x_s+1)
        LD      D,A
        LD      A,(.y_s)
        LD      C,A
        LD      E,A
        CALL    .line
        LD      A,(.x_s)
        LD      B,A
        LD      A,(.x_s+1)
        LD      D,A
        LD      A,(.y_s+1)
        LD      C,A
        LD      E,A
        CALL    .line
        LD      A,(.style)
        OR      A
        RET     Z
        LD      A,(.x_s)
        LD      B,A
        LD      A,(.x_s+1)
        SUB     B
        RET     C
        LD      A,(.y_s)
        INC     A
        LD      (.y_s),A
        LD      A,(.y_s+1)
        DEC     A
        LD      (.y_s+1),A
        LD      A,(.y_s)
        LD      B,A
        LD      A,(.y_s+1)
        SUB     B
        RET     C

        LD      A,(.fg_colour)
        LD      C,A
        LD      A,(.bg_colour)
        LD      (.fg_colour),A
        LD      A,C
        LD      (.bg_colour),A
filllp$:
        LD      A,(.x_s)
        LD      B,A
        LD      A,(.x_s+1)
        LD      D,A
        LD      A,(.y_s)
        LD      C,A
        LD      E,A
        CALL    .line
        LD      A,(.y_s+1)
        LD      B,A
        LD      A,(.y_s)
        CP      B
        JR      Z,swap$
        INC     A
        LD      (.y_s),A
        JR      filllp$
swap$:
        LD      A,(.fg_colour)
        LD      C,A
        LD      A,(.bg_colour)
        LD      (.fg_colour),A
        LD      A,C
        LD      (.bg_colour),A
        RET

        ;; Draw a line between (B,C) and (D,E)
.line::
        LD      A,C     ;Calculate Delta Y
        SUB     E
        JR      NC,s1$
        CPL
        INC     A

s1$:    LD      (.delta_y),A
        LD      H,A

        LD      A,B     ;Calculate Delta X
        SUB     D
        JR      NC,s2$
        CPL
        INC     A

s2$:    LD      (.delta_x),A

        SUB     H
        JP      C,y1

        ;; Use Delta X

        LD      A,B
        SUB     D
        JP      NC,x2$

        LD      A,C
        SUB     E
        JR      Z,x3$
        LD      A,#0x00
        JR      NC,x3$
        LD      A,#0xFF
        JR      x3$

x2$:
        LD      A,E
        SUB     C
        JR      Z,x2a$
        LD      A,#0x00
        JR      NC,x2a$
        LD      A,#0xFF

x2a$:
        LD      B,D
        LD      C,E     ;BC holds start X,Y
x3$:
        LD      (.l_inc),A      ;Store Y increment
        LD      HL,#.y_table
        LD      D,#0x00
        LD      E,C
        ADD     HL,DE
        ADD     HL,DE
        LD      A,(HL+)
        LD      H,(HL)
        LD      L,A

        LD      A,B
        AND     #0xf8
        LD      E,A
        ADD     HL,DE
        ADD     HL,DE

        LD      A,(.delta_y)
        OR      A
        JP      Z,.xonly

        ;;      Got to do it the hard way.

        ;       Calculate (2*deltay) -> dinc1

        PUSH    HL
        LD      H,#0x00
        LD      L,A
        ADD     HL,HL
        LD      A,H
        LD      (.dinc1),A
        LD      A,L
        LD      (.dinc1+1),A

        ;       Calculate (2*deltay)-deltax -> d


        LD      D,H
        LD      E,L
        LD      A,(.delta_x)
        CPL
        LD      L,A
        LD      H,#0xFF
        INC     HL
dx1$:
        ADD     HL,DE
        LD      A,H
        LD      (.l_d),A
        LD      A,L
        LD      (.l_d+1),A

        ;       Calculate (deltay-deltax)*2 -> dinc2

        LD      A,(.delta_x)
        CPL
        LD      L,A
        LD      H,#0xFF
        INC     HL
        LD      A,(.delta_y)
        LD      D,#0x00
        LD      E,A
        ADD     HL,DE
        ADD     HL,HL

        LD      A,H
        LD      (.dinc2),A
        LD      A,L
        LD      (.dinc2+1),A

        POP     HL

        LD      A,(.delta_x)
        LD      E,A

        LD      A,B
        AND     #7
        ADD     #<.drawing_bits_tbl     ; Table of bits is located at 0x0070
        LD      C,A
        LD      B,#0x00
        LD      A,(BC)  ; Get start bit
        LD      B,A
        LD      C,A

xloop$:
        RRC     C
        LD      A,(.l_d)
        BIT     7,A
        JR      Z,ychg$
        PUSH    DE
        BIT     7,C
        JR      Z,nbit$
        LD      A,B
        CPL
        LD      C,A
        CALL    .wrbyte
        DEC     HL
        LD      C,#0x80
        LD      B,C
nbit$:
        LD      A,(.l_d+1)
        LD      D,A
        LD      A,(.dinc1+1)
        ADD     D
        LD      (.l_d+1),A
        LD      A,(.l_d)
        LD      D,A
        LD      A,(.dinc1)
        ADC     D
        LD      (.l_d),A
        POP     DE
        JR      nchg$
ychg$:
        PUSH    DE
        PUSH    BC
        LD      A,B
        CPL
        LD      C,A
        CALL    .wrbyte
        LD      A,(.l_inc)
        OR      A
        JR      Z,ydown$
        INC     HL
        LD      A,L
        AND     #0x0F
        JR      NZ,bound$
        LD      DE,#0x0130
        ADD     HL,DE   ;Correct screen address
        JR      bound$
ydown$:
        DEC     HL
        DEC     HL
        DEC     HL
        LD      A,L
        AND     #0x0F
        XOR     #0x0E
        JR      NZ,bound$
        LD      DE,#0xFED0
        ADD     HL,DE   ;Correct screen address
bound$:
        LD      A,(.l_d+1)
        LD      D,A
        LD      A,(.dinc2+1)
        ADD     D
        LD      (.l_d+1),A
        LD      A,(.l_d)
        LD      D,A
        LD      A,(.dinc2)
        ADC     D
        LD      (.l_d),A
        POP     BC
        LD      B,C
        POP     DE
nchg$:
        BIT     7,C
        JR      Z,nadj$
        PUSH    DE
        LD      DE,#0x0010
        ADD     HL,DE   ;Correct screen address
        POP     DE
        LD      B,C
nadj$:
        LD      A,B
        OR      C
        LD      B,A
        DEC     E
        JP      NZ,xloop$
        LD      A,B
        CPL
        LD      C,A
        JP      .wrbyte

.xonly::
        ;; Draw accelerated horizontal line

        LD      A,(.delta_x)
        LD      E,A
        INC     E

        LD      A,B     ;check X
        AND     #7      ;just look at bottom 3 bits
        JR      Z,2$
        PUSH    HL
        ADD     #<.drawing_bits_tbl     ;Table of bits is located at 0x0070
        LD      L,A
        LD      H,#0x00
        LD      C,(HL)
        POP     HL
        XOR     A       ;Clear A
1$:     RRCA            ;Shift data right 1
        OR      C
        DEC     E
        JR      Z,3$
        BIT     0,A
        JR      Z,1$
        JR      3$
2$:
        LD      A,E
        DEC     A
        AND     #0xF8
        JR      Z,4$
        JR      8$
3$:
        LD      B,A
        CPL
        LD      C,A
        PUSH    DE
        CALL    .wrbyte
        LD      DE,#0x0F
        ADD     HL,DE   ;Correct screen address
        POP     DE

8$:     LD      A,E
        OR      A
        RET     Z
        AND     #0xF8
        JR      Z,4$

        XOR     A
        LD      C,A
        CPL
        LD      B,A

        PUSH    DE
        CALL    .wrbyte
        LD      DE,#0x0F
        ADD     HL,DE   ;Correct screen address
        POP     DE
        LD      A,E
        SUB     #8
        RET     Z
        LD      E,A
        JR      8$

4$:     LD      A,#0x80
5$:     DEC     E
        JR      Z,6$
        SRA     A
        JR      5$
6$:     LD      B,A
        CPL
        LD      C,A
        JP      .wrbyte

        ;; Use Delta Y
y1:
        LD      A,C
        SUB     E
        JP      NC,y2$

        LD      A,B
        SUB     D
        JR      Z,y3$
        LD      A,#0x00
        JR      NC,y3$
        LD      A,#0xFF
        JR      y3$

y2$:
        LD      A,C
        SUB     E
        JR      Z,y2a$
        LD      A,#0x00

;       JR      NC,y2a$ ; old code; fix draw to up-left below
;       LD      A,#0xFF

        LD      L,A     ; invert delta if x1 less than x2
        LD      A,B
        SUB     D
        LD      A,L
        JR      C,y2a$
        CPL

y2a$:
        LD      B,D
        LD      C,E     ;BC holds start X,Y

y3$:
        LD      (.l_inc),A      ;Store X increment
        LD      HL,#.y_table
        LD      D,#0x00
        LD      E,C
        ADD     HL,DE
        ADD     HL,DE
        LD      A,(HL+)
        LD      H,(HL)
        LD      L,A

        LD      A,B
        AND     #0xf8
        LD      E,A
        ADD     HL,DE
        ADD     HL,DE

        LD      A,(.delta_y)
        LD      E,A
        INC     E

        LD      A,(.delta_x)
        OR      A
        JP      Z,.yonly

        ;;      Got to do it the hard way.

        ;       Calculate (2*deltax) -> dinc1

        PUSH    HL
        LD      H,#0x00
        LD      L,A
        ADD     HL,HL
        LD      A,H
        LD      (.dinc1),A
        LD      A,L
        LD      (.dinc1+1),A

        ;       Calculate (2*deltax)-deltay -> d


        LD      D,H
        LD      E,L
        LD      A,(.delta_y)
        CPL
        LD      L,A
        LD      H,#0xFF
        INC     HL
dy1$:
        ADD     HL,DE
        LD      A,H
        LD      (.l_d),A
        LD      A,L
        LD      (.l_d+1),A

        ;       Calculate (deltax-deltay)*2 -> dinc2

        LD      A,(.delta_y)
        CPL
        LD      L,A
        LD      H,#0xFF
        INC     HL
        LD      A,(.delta_x)
        LD      D,#0x00
        LD      E,A
        ADD     HL,DE
        ADD     HL,HL

        LD      A,H
        LD      (.dinc2),A
        LD      A,L
        LD      (.dinc2+1),A

        POP     HL

        LD      A,(.delta_y)
        LD      E,A

        LD      A,B
        AND     #7
        ADD     #<.drawing_bits_tbl     ; Table of bits is located at 0x0070
        LD      C,A
        LD      B,#0x00
        LD      A,(BC)  ; Get start bit
        LD      B,A
        LD      C,A

yloop$:
        PUSH    DE
        PUSH    BC
        LD      A,B
        CPL
        LD      C,A
        CALL    .wrbyte
        INC     HL
        LD      A,L
        AND     #0x0F
        JR      NZ,nybound$
        LD      DE,#0x0130
        ADD     HL,DE   ;Correct screen address
nybound$:
        POP     BC
        LD      A,(.l_d)
        BIT     7,A
        JR      Z,xchg$
        LD      A,(.l_d+1)
        LD      D,A
        LD      A,(.dinc1+1)
        ADD     D
        LD      (.l_d+1),A
        LD      A,(.l_d)
        LD      D,A
        LD      A,(.dinc1)
        ADC     D
        LD      (.l_d),A
        JR      nchgy$
xchg$:
        LD      A,(.l_inc)
        OR      A
        JR      NZ,yright$
        RLC     B
        BIT     0,B
        JR      Z,boundy$
        LD      DE,#0xFFF0
        ADD     HL,DE   ;Correct screen address
        JR      boundy$
yright$:
        RRC     B
        BIT     7,B
        JR      Z,boundy$
        LD      DE,#0x0010
        ADD     HL,DE   ;Correct screen address
boundy$:
        LD      A,(.l_d+1)
        LD      D,A
        LD      A,(.dinc2+1)
        ADD     D
        LD      (.l_d+1),A
        LD      A,(.l_d)
        LD      D,A
        LD      A,(.dinc2)
        ADC     D
        LD      (.l_d),A
nchgy$:
        POP     DE
        DEC     E
        JR      NZ,yloop$
        LD      A,B
        CPL
        LD      C,A
        JP      .wrbyte

.yonly::
        ;; Draw accelerated vertical line
        LD      A,B     ;check X
        AND     #7      ;just look at bottom 3 bits
        PUSH    HL
        ADD     #<.drawing_bits_tbl     ;Table of bits is located at 0x0070
        LD      L,A
        LD      H,#0x00
        LD      A,(HL)  ;Get mask bit
        POP     HL
        LD      B,A
        CPL
        LD      C,A

1$:     PUSH    DE
        CALL    .wrbyte
        INC     HL      ;Correct screen address
        LD      A,L
        AND     #0x0F
        JR      NZ,2$
        LD      DE,#0x0130
        ADD     HL,DE
2$:     POP     DE
        DEC     E
        RET     Z
        JR      1$

        ;; Draw a point at (B,C) with mode and color D
.plot::

        LD      HL,#.y_table
        LD      D,#0x00
        LD      E,C
        ADD     HL,DE
        ADD     HL,DE
        LD      A,(HL+)
        LD      H,(HL)
        LD      L,A

        LD      A,B
        AND     #0xf8
        LD      E,A
        ADD     HL,DE
        ADD     HL,DE

        LD      A,B

        AND     #7
        ADD     #<.drawing_bits_tbl             ; Table of bits is located at 0x0070
        LD      C,A
        LD      B,#0x00
        LD      A,(BC)
        LD      B,A
        CPL
        LD      C,A

.wrbyte::
        LD      A,(.fg_colour)
        LD      D,A
        LD      A,(.draw_mode)
        CP      #.M_OR
        JR      Z,10$
        CP      #.M_XOR
        JR      Z,20$
        CP      #.M_AND
        JR      Z,30$

        ; Fall through to SOLID by default
1$:
        ;; Solid
        LD      E,B
        BIT     0,D
        JR      NZ,2$
        PUSH    BC
        LD      B,#0x00
2$:
        BIT     1,D
        JR      NZ,3$
        LD      E,#0x00
3$:
        WAIT_STAT

        LD      A,(HL)
        AND     C
        OR      B
        LD      (HL+),A

        LD      A,(HL)
        AND     C
        OR      E
        LD      (HL),A
        LD      A,B
        OR      A
        RET     NZ
        POP     BC
        RET

10$:
        ;; Or
        LD      C,B
        BIT     0,D
        JR      NZ,11$
        LD      B,#0x00
11$:
        BIT     1,D
        JR      NZ,12$
        LD      C,#0x00
12$:
        WAIT_STAT

        LD      A,(HL)
        OR      B
        LD      (HL+),A

        WAIT_STAT

        LD      A,(HL)
        OR      C
        LD      (HL),A
        RET

20$:
        ;; Xor
        LD      C,B
        BIT     0,D
        JR      NZ,21$
        LD      B,#0x00
21$:
        BIT     1,D
        JR      NZ,22$
        LD      C,#0x00
22$:
        WAIT_STAT

        LD      A,(HL)
        XOR     B
        LD      (HL+),A

        WAIT_STAT

        LD      A,(HL)
        XOR     C
        LD      (HL),A
        RET

30$:
        ;; And
        LD      B,C
        BIT     0,D
        JR      Z,31$
        LD      B,#0xFF
31$:
        BIT     1,D
        JR      Z,32$
        LD      C,#0xFF
32$:
        WAIT_STAT

        LD      A,(HL)
        AND     B
        LD      (HL+),A

        WAIT_STAT

        LD      A,(HL)
        AND     C
        LD      (HL),A
        RET

        ;; Get color of pixel at point (B,C) returns in A
.getpix::
        LD      HL,#.y_table
        LD      D,#0x00
        LD      E,C
        ADD     HL,DE
        ADD     HL,DE
        LD      A,(HL+)
        LD      H,(HL)
        LD      L,A

        LD      A,B
        AND     #0xf8
        LD      E,A
        ADD     HL,DE
        ADD     HL,DE

        LD      A,B

        AND     #7
        ADD     #<.drawing_bits_tbl             ; Table of bits is located at 0x0070
        LD      C,A
        LD      B,#0x00
        LD      A,(BC)
        LD      C,A

        WAIT_STAT

        LD      A,(HL+)
        LD      D,A
        LD      A,(HL+)
        LD      E,A
        LD      B,#0
        LD      A,D
        AND     C
        JR      Z,1$
        SET     0,B
1$:     LD      A,E
        AND     C
        JR      Z,2$
        SET     1,B
2$:     LD      E,B
        RET

        ;; Write character C
.wrtchr::
        LD      HL,#.y_table
        LD      D,#0x00
        LD      A,(.ty)
        RLCA
        RLCA
        RLCA
        LD      E,A
        ADD     HL,DE
        ADD     HL,DE
        LD      A,(HL+)
        LD      B, A
        LD      H,(HL)
        LD      L,B

        LD      A,(.tx)
        RLCA
        RLCA
        RLCA
        LD      E,A
        ADD     HL,DE
        ADD     HL,DE

        LD      A,C
        LD      B,H
        LD      C,L

        LD      H,D
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL

        .globl  _font_ibm_fixed_tiles

        LD      DE,#_font_ibm_fixed_tiles

        ADD     HL,DE

        LD      D,H
        LD      E,L
        LD      H,B
        LD      L,C

        LD      A,(.fg_colour)
        LD      C,A
1$:
        LD      A,(DE)
        INC     DE
        PUSH    DE

        PUSH    HL
        LD      HL,#.bg_colour
        LD      L,(HL)

        LD      B,A
        XOR     A
        BIT     0,L
        JR      Z,2$
        CPL
2$:     OR      B
        BIT     0,C
        JR      NZ,3$
        XOR     B
3$:     LD      D,A
        XOR     A
        BIT     1,L
        JR      Z,4$
        CPL
4$:     OR      B
        BIT     1,C
        JR      NZ,5$
        XOR     B
5$:
        LD      E,A
        POP     HL

        WAIT_STAT

        LD      A,D
        LD      (HL+),A
        LD      A,E
        LD      (HL+),A
        POP     DE
        LD      A,L
        AND     #0x0F
        JR      NZ,1$
        RET

_gotogxy::
        LDA     HL,2(SP)        ; Skip return address
        LD      A,(HL+)         ; A = x
        LD      (.tx),A
        LD      A,(HL+)         ; A = y
        LD      (.ty),A

        RET

_wrtchr::
        PUSH    BC

        LD      A,(.mode)
        CP      #.G_MODE
        CALL    NZ,.gmode

        LDA     HL,4(SP)        ; Skip return address and registers
        LD      A,(HL)
        LD      C,A     ; C = Char to print

        CALL    .wrtchr
        CALL    .adv_gcurs

        POP     BC
        RET

_getpix::
        PUSH    BC

        LDA     HL,4(SP)        ; Skip return address and registers
        LD      A,(HL+) ; B = x
        LD      B,A
        LD      A,(HL+) ; C = y
        LD      C,A

        CALL    .getpix

        POP     BC
        RET

_circle::
        PUSH    BC

        LD      A,(.mode)
        CP      #.G_MODE
        CALL    NZ,.gmode

        LDA     HL,4(SP)        ; Skip return address and registers
        LD      A,(HL+) ; B = x
        LD      B,A
        LD      A,(HL+) ; C = y
        LD      C,A
        LD      A,(HL+) ; D = Radius
        LD      D,A
        LD      A,(HL)
        LD      (.style),A

        CALL    .circle

        POP     BC
        RET

_box::
        PUSH    BC

        LD      A,(.mode)
        CP      #.G_MODE
        CALL    NZ,.gmode

        LDA     HL,4(SP)        ; Skip return address and registers
        LD      A,(HL+) ; B = x1
        LD      (.x_s),A
        LD      A,(HL+) ; C = y1
        LD      (.y_s),A
        LD      A,(HL+) ; D = x2
        LD      (.x_s+1),A
        LD      A,(HL+) ; E = y2
        LD      (.y_s+1),A
        LD      A,(HL)
        LD      (.style),A
        CALL    .box
        POP     BC
        RET

_line::
        PUSH    BC

        LD      A,(.mode)
        CP      #.G_MODE
        CALL    NZ,.gmode

        LDA     HL,4(SP)        ; Skip return address and registers
        LD      A,(HL+) ; B = x1
        LD      B,A
        LD      A,(HL+) ; C = y1
        LD      C,A
        LD      A,(HL+) ; D = x2
        LD      D,A
        LD      A,(HL+) ; E = y2
        LD      E,A

        CALL    .line

        POP     BC
        RET

_plot_point::
        PUSH    BC

        LD      A,(.mode)
        CP      #.G_MODE
        CALL    NZ,.gmode

        LDA     HL,4(SP)        ; Skip return address and registers
        LD      A,(HL+) ; B = x
        LD      B,A
        LD      A,(HL+) ; C = y
        LD      C,A

        CALL    .plot

        POP     BC
        RET

        ;; Old, compatible version of plot()
_plot::
        PUSH    BC

        LD      A,(.mode)
        CP      #.G_MODE
        CALL    NZ,.gmode

        LDA     HL,4(SP)        ; Skip return address and registers
        LD      A,(HL+)         ; B = x
        LD      B,A
        LD      A,(HL+)         ; C = y
        LD      C,A
        LD      A,(HL+)         ; colour
        LD      (.fg_colour),A
        LD      A,(HL+)         ; mode
        LD      (.draw_mode),A

        CALL    .plot

        POP     BC
        RET

_switch_data::                  ; Non Banked as pointer
        PUSH    BC

        LD      A,(.mode)
        CP      #.G_MODE
        CALL    NZ,.gmode

        LDA     HL,4(SP)        ; Skip return address and registers
        LD      A,(HL+) ; B = x
        LD      B,A
        LD      A,(HL+) ; C = y
        LD      C,A
        LD      A,(HL+) ; DE = src
        LD      E,A
        LD      A,(HL+)
        LD      D,A
        LD      A,(HL+) ; HL = dst
        LD      H,(HL)
        LD      L,A

        CALL    .switch_data

        POP     BC
        RET


_draw_image::                   ; Non banked as pointer
        LD      A,(.mode)
        CP      #.G_MODE
        CALL    NZ,.gmode

        LD      H, D
        LD      L, E

.draw_image::
        LD      DE,#0x8000+0x10*0x10
        LD      BC,#0x1680
        JP      .copy_vram      ; Move the charset


.y_table::
        .word   0x8100,0x8102,0x8104,0x8106,0x8108,0x810A,0x810C,0x810E
        .word   0x8240,0x8242,0x8244,0x8246,0x8248,0x824A,0x824C,0x824E
        .word   0x8380,0x8382,0x8384,0x8386,0x8388,0x838A,0x838C,0x838E
        .word   0x84C0,0x84C2,0x84C4,0x84C6,0x84C8,0x84CA,0x84CC,0x84CE
        .word   0x8600,0x8602,0x8604,0x8606,0x8608,0x860A,0x860C,0x860E
        .word   0x8740,0x8742,0x8744,0x8746,0x8748,0x874A,0x874C,0x874E
        .word   0x8880,0x8882,0x8884,0x8886,0x8888,0x888A,0x888C,0x888E
        .word   0x89C0,0x89C2,0x89C4,0x89C6,0x89C8,0x89CA,0x89CC,0x89CE
        .word   0x8B00,0x8B02,0x8B04,0x8B06,0x8B08,0x8B0A,0x8B0C,0x8B0E
        .word   0x8C40,0x8C42,0x8C44,0x8C46,0x8C48,0x8C4A,0x8C4C,0x8C4E
        .word   0x8D80,0x8D82,0x8D84,0x8D86,0x8D88,0x8D8A,0x8D8C,0x8D8E
        .word   0x8EC0,0x8EC2,0x8EC4,0x8EC6,0x8EC8,0x8ECA,0x8ECC,0x8ECE
        .word   0x9000,0x9002,0x9004,0x9006,0x9008,0x900A,0x900C,0x900E
        .word   0x9140,0x9142,0x9144,0x9146,0x9148,0x914A,0x914C,0x914E
        .word   0x9280,0x9282,0x9284,0x9286,0x9288,0x928A,0x928C,0x928E
        .word   0x93C0,0x93C2,0x93C4,0x93C6,0x93C8,0x93CA,0x93CC,0x93CE
        .word   0x9500,0x9502,0x9504,0x9506,0x9508,0x950A,0x950C,0x950E
        .word   0x9640,0x9642,0x9644,0x9646,0x9648,0x964A,0x964C,0x964E
