* MAINMEM.SHR.S
* (c) Bobbi 2022 GPLv3
*
* Routines for drawing bitmapped text and graphics in SHR mode
* on Apple IIGS (640x200 4 colour, or 320x200 16 colour.)
*
* This code is in main memory only to save space in aux LC.
*

******************************************************************************
* Data in bank $E1
******************************************************************************

SHRFONTXPLD   EQU   $A000                  ; Explode SHR font to $E1:A000

******************************************************************************

* 21 bytes of persistent storage, also accessed by mainmem code
* TODO: Move to SHRZP maybe
SHRPIXELS     DB    $00                    ; Main memory copy of VDUPIXELS
SHRVDUQ       DS    16                     ; Main memory copy of VDUQ
SHRGFXFGMASK  DB    $00                    ; Foreground colour mask
SHRGFXFGMSK2  DB    $00                    ; Copy of foreground colour mask
SHRGFXBGMASK  DB    $00                    ; Background colour mask
SHRGFXACTION  DB    $00                    ; GCOL action for point plotting

* These are all persistent locals (14 bytes of ZP)
SHRXPIXEL     EQU   SHRZP+0                ; Prev point in screen coords (word)
SHRYPIXEL     EQU   SHRZP+2                ; Prev point in screen coords (word)
SHRWINLFT     EQU   SHRZP+4                ; Gfx win - left (0-639) (word)
SHRWINRGT     EQU   SHRZP+6                ; Gfx win - right (0-639) (word)
SHRWINTOP     EQU   SHRZP+8                ; Gfx win - top (0-199) (word)
SHRWINBTM     EQU   SHRZP+10               ; Gfx win - bottom (0-199) (word)


* Colours in the following order.
* For 16 colour modes ...
* BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, ...
* For 4 colour modes ...
* BLACK, RED, YELLOW, WHITE

*                    GB   0R
PALETTE320    DB    $00, $00               ; BLACK
              DB    $00, $0F               ; RED
              DB    $F0, $00               ; GREEN
              DB    $F0, $0F               ; YELLOW
              DB    $0F, $00               ; BLUE
              DB    $0F, $0F               ; MAGENTA
              DB    $FF, $00               ; CYAN
              DB    $FF, $0F               ; WHITE
              DB    $44, $04               ; Dark grey
              DB    $88, $0F               ; RED (light)
              DB    $F8, $08               ; GREEN (light)
              DB    $F8, $0F               ; YELLOW (light)
              DB    $8F, $08               ; BLUE (light)
              DB    $8F, $0F               ; MAGENTA (light)
              DB    $FF, $08               ; CYAN (light)
              DB    $AA, $0A               ; Light grey

PALETTE640    DB    $00, $00               ; BLACK
              DB    $00, $0F               ; RED
              DB    $F0, $0F               ; YELLOW
              DB    $FF, $0F               ; WHITE
              DB    $00, $00               ; BLACK
              DB    $00, $0F               ; RED
              DB    $F0, $0F               ; YELLOW
              DB    $F8, $0F               ; WHITE
              DB    $00, $00               ; BLACK
              DB    $00, $0F               ; RED
              DB    $F0, $0F               ; YELLOW
              DB    $FF, $0F               ; WHITE
              DB    $00, $00               ; BLACK
              DB    $00, $0F               ; RED
              DB    $F0, $0F               ; YELLOW
              DB    $FF, $0F               ; WHITE


* Explode font to generate SHRFONTXPLD table
* This is 2 bytes x 8 rows for each character in 640 mode
* or      4 bytes x 8 rows for each character in 320 mode
SHRXPLDFONT   >>>   ENTMAIN
              LDA   #<SHRFONTXPLD          ; Use A3L/H to point to ..
              STA   A3L                    ; .. start of table to write
              LDA   #>SHRFONTXPLD
              STA   A3H
              LDA   #$E1                   ; Memory bank $E1
              STA   A4L
              LDA   #32                    ; First char number
:L1           JSR   SHRXPLDCHAR            ; Explode char A
              INC   A
              CMP   #128                   ; 96 chars in FONT8
              BNE   :L1
              >>>   XF2AUX,SHRV22RET
              RTS


* Explode one character to location pointed to by A3L
* On entry: A - character to explode
SHRXPLDCHAR   PHA
              SEC
              SBC   #32
              STA   A1L                    ; A*8 -> A1L/H
              STZ   A1H
              ASL   A1L
              ROL   A1H
              ASL   A1L
              ROL   A1H
              ASL   A1L
              ROL   A1H
              CLC                          ; FONT8+A*8 -> A1L/H
              LDA   A1L
              ADC   #<FONT8
              STA   A1L
              LDA   A1H
              ADC   #>FONT8
              STA   A1H
              LDY   #$00                   ; First row of char
:L1           LDA   (A1L),Y                ; Load row of font
              JSR   SHRXPLDROW
              INY                          ; Next row of font
              CPY   #$08                   ; Last row?
              BNE   :L1
              PLA
              RTS


* Explode one pixel row of user defined graphics char
SHRUSERCHAR   >>>   ENTMAIN
              LDA   #<SHRFONTXPLD          ; Use A3L/H to point to ..
              STA   A3L                    ; .. start of table to write
              LDA   #>SHRFONTXPLD
              STA   A3H
              LDA   #$E1                   ; Bank $E1
              STA   A4L

              LDA   SHRVDUQ+0              ; Character number
              CMP   #32                    ; < 32? Then bail out
              BCC   :DONE
              SEC                          ; Otherwise, subtract 32
              SBC   #32
              TAY

              LDA   #16                    ; Bytes/char in 640 mode              
              LDX   SHRPIXELS              ; Pixels per byte
              CPX   #$02                   ; 2 is 320-mode (MODE 1)
              BNE   :S0
              LDA   #32                    ; Bytes/char in 320 mode
:S0           STA   :INCREMENT

:L0           CPY   #$00
              BEQ   :S1
              CLC
              LDA   A3L
              ADC   :INCREMENT
              STA   A3L
              LDA   A3H
              ADC   #$00
              STA   A3H
              DEY
              BRA   :L0

:S1           LDY   #$00
:L1           LDA   SHRVDUQ+1,Y            ; Row of pixels
              JSR   SHRXPLDROW
              INY
              CPY   #$08                   ; Last row?
              BNE   :L1
:DONE         >>>   XF2AUX,VDUXXRET
:INCREMENT    DB    $00


* Explode one row of pixels. Used by SHRXPLDCHAR & SHRUSERCHAR
* On entry: A contains row of font data
SHRXPLDROW    LDX   SHRPIXELS              ; Pixels per byte
              CPX   #$02                   ; 2 is 320-mode (MODE 1)
              BNE   :S1
              JSR   SHRCHAR320
              BRA   :S2
:S1           JSR   SHRCHAR640
:S2           LDX   SHRPIXELS              ; Pixels per byte
              CPX   #$02                   ; 2 is 320-mode (MODE 1)
              BNE   :S3
              CLC                          ; 320 mode: add 4 to A3L
              LDA   A3L
              ADC   #$04
              STA   A3L
              LDA   A3H
              ADC   #$00
              STA   A3H
              BRA   :S4
:S3           CLC                          ; 640 mode: add 2 to A3L
              LDA   A3L
              ADC   #$02
              STA   A3L
              LDA   A3H
              ADC   #$00
              STA   A3H
:S4           RTS


* Explode one pixel row of font in 320 mode
* 4 bytes per char, 4 bits per pixel
* On entry: A contains row of font data
SHRCHAR320    PHY                          ; Preserve Y
              LDY   #$00                   ; Dest byte index
:L0           STZ   A2L
              LDX   #$00                   ; Source bit index
:L1           ASL                          ; MS bit -> C
              PHP                          ; Preserve C
              ROL   A2L                    ; C -> LS bit
              PLP                          ; Recover C
              PHP
              ROL   A2L                    ; C -> LS bit
              PLP                          ; Recover C
              PHP
              ROL   A2L                    ; C -> LS bit
              PLP                          ; Recover C
              ROL   A2L                    ; C -> LS bit
              INX
              CPX   #$02                   ; Processed two bits of font?
              BNE   :L1
              PHA                          ; Preserve partially shifted font
              LDA   A2L
              STA   [A3L],Y
              PLA                          ; Recover partially shifted font
              INY
              CPY   #$04                   ; Done 4 bytes?
              BNE   :L0
              PLY                          ; Recover Y
              RTS


* Explode one pixel row of font in 640 mode
* 2 bytes per char, 2 bits per pixel
* On entry: A contains row of font data
SHRCHAR640    PHY                          ; Preserve Y
              LDY   #$00                   ; Dest byte index
:L0           STZ   A2L
              LDX   #$00                   ; Source bit index
:L1           ASL                          ; MS bit -> C
              PHP                          ; Preserve C
              ROL   A2L                    ; C -> LS bit
              PLP                          ; Recover C
              ROL   A2L                    ; C -> LS bit
              INX
              CPX   #$04
              BNE   :L1
              PHA                          ; Preserve partially shifted font
              LDA   A2L
              STA   [A3L],Y
              PLA                          ; Recover partially shifted font
              INY
              CPY   #$02                   ; Done 2 bytes?
              BNE   :L0
              PLY                          ; Recover Y
              RTS


* VDU5 plot char at graphics cursor position
SHRVDU5CH     >>>   ENTMAIN
*              PHP                          ; Disable interrupts
*              SEI
              CLC                          ; 65816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin

              AND   #$00FF
              STA   A1L                    ; A*16 -> A1L/H
              ASL   A1L
              ASL   A1L
              ASL   A1L
              ASL   A1L

              LDA   SHRPIXELS              ; Pixels per byte
              AND   #$00FF
              CMP   #$02                   ; 2 is 320-mode (MODE 1)
              BNE   :MODE0
              LDA   #$04                   ; 4 bytes per row in MODE 1
              ASL   A1L                    ; A*32 -> A1L/H in MODE 1
              BRA   :S0
:MODE0        LDA   #$02                   ; 2 bytes per row in MODE 0
:S0           STA   :BYTES

              CLC                          ; Add SHRFONTXPLD to A1L/H
              LDA   A1L
              ADC   #SHRFONTXPLD
              STA   A1L

              LDA   SHRYPIXEL              ; y coordinate
              SEC
              SBC   #8                     ; Height of this row
              CMP   SHRWINBTM
              BMI   :NEWPAGE
              LDA   SHRYPIXEL
              CMP   SHRWINTOP
              BEQ   :S1
              BPL   :NEWPAGE
:S1           LDA   SHRXPIXEL              ; x coordinate
              CMP   SHRWINLFT
              BMI   :NEWPAGE
              CMP   SHRWINRGT
              BEQ   :S2
              BPL   :NEWPAGE
              BRA   :S2
:NEWPAGE      LDA   SHRWINTOP
              STA   SHRYPIXEL
              LDA   SHRWINLFT
              STA   SHRXPIXEL

:S2           SEP   #$30                   ; 8 bit M & X
              MX    %11                    ; Tell Merlin
              LDX   SHRYPIXEL              ; Screen row (Y-coord)
              LDA   SHRROWSL,X             ; Look up addr (LS byte)
              STA   A3L                    ; Stash in A3L
              LDA   SHRROWSH,X             ; Look up addr (MS byte)
              STA   A3H                    ; Stash in A3H
              LDA   #$E1                   ; Bank $E1
              STA   A4L
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin

              LDX   SHRXPIXEL              ; Screen col (X-coord)
              STX   A2L
              LSR   A2L                    ; Divide by 2

              LDA   SHRPIXELS
              AND   #$00FF
              CMP   #$02
              BEQ   :M1                    ; MODE 1
              LSR   A2L                    ; Divide by 2 again
:M1           LDX   A1L                    ; Index into exploded font
              STZ   :ROWCTR
:L0           
              PHX
              LDY   #$00
              STZ   :PIXBUF+2              ; Clear bytes 3,4 of shift buf
              STZ   :PIXBUF+4              ; Clear bytes 5,6 of shift buf
:LOOP         LDAL  $E10000,X              ; Read a word of exploded font
              STA   :PIXBUF,Y              ; Store word to shift buffer
              INX
              INX
              INY
              INY
              CPY   :BYTES
              BNE   :LOOP
              LDA   SHRXPIXEL
              JSR   SHRSHIFT               ; Shift :PIXBUF to the right
              LDY   A2L                    ; Index into row of pixels
              STZ   :COLCTR
              LDX   #$00
              INC   :BYTES
:L1           LDA   :PIXBUF,X              ; Read word of exploded font
              PHX
              SEP   #$30                   ; 8 bit M & X
              MX    %11                    ; Tell Merlin
              JSR   SHRPLOTBYTE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              PLX
              INX                          ; Next byte of font
              INY                          ; Next byte on screen
              INC   :COLCTR
              LDA   :COLCTR
              CMP   :BYTES                 ; Bytes per row 
              BNE   :L1
              DEC   :BYTES

              PLA                          ; Restore saved X -> A
              CLC                          ; Add bytes per row
              ADC   :BYTES
              TAX                          ; Back to X

              LDA   A3L                    ; Increment A3L/H to next row
              CLC
              ADC   #$A0
              STA   A3L
              LDA   A3H
              ADC   #$00
              STA   A3H
              INC   :ROWCTR
              LDA   :ROWCTR
              CMP   #$08                   ; 8 rows
              BNE   :L0
:DONE         SEC                          ; 65816 emulation mode
              XCE
              MX    %11                    ; Tell Merlin
*              PLP
              >>>   XF2AUX,SHRPRCH320RET
* Zero page
:COLCTR       EQU   TMPZP+0
:ROWCTR       EQU   TMPZP+2
:BYTES        EQU   TMPZP+4                ; Bytes per char row
:PIXBUF       EQU   TMPZP+6                ; Shift buffer (6 bytes)


* Shifts one character row of pixels to the right
* Called in 65816 native mode, 16 bit M & X
* On entry: A - x-coordinate of char
SHRSHIFT      MX    %00                    ; Tell merlin we are 16 bit M&X
              PHA
              LDA   SHRPIXELS              ; Pixels per byte
              AND   #$00FF
              CMP   #$02                   ; 2 is 320-mode (MODE 1)
              BNE   :MODE0
              PLA
              AND   #$0001                 ; Bits to shift in MODE 1
              ASL
              PHA
:MODE0        PLA
              AND   #$0003                 ; Bits to shift in MODE 0
              PHA

              LDA   :PIXBUF                ; Put bytes in big-endian order
              XBA
              STA   :PIXBUF
              LDA   :PIXBUF+2
              XBA
              STA   :PIXBUF+2
              LDA   :PIXBUF+4
              XBA
              STA   :PIXBUF+4

              PLA
:L1           CMP   #$0000
              BEQ   :S1
              LSR   :PIXBUF                ; Shift :PIXBUF to the right 1 bit
              ROR   :PIXBUF+2
              ROR   :PIXBUF+4
              LSR   :PIXBUF                ; Shift right again
              ROR   :PIXBUF+2
              ROR   :PIXBUF+4
              DEC   A
              BRA   :L1

:S1           LDA   :PIXBUF                ; Put bytes back in little-endian
              XBA
              STA   :PIXBUF
              LDA   :PIXBUF+2
              XBA
              STA   :PIXBUF+2
              LDA   :PIXBUF+4
              XBA
              STA   :PIXBUF+4
              RTS
              MX    %11


* Handle cursor left in VDU5 mode
SHRVDU08      >>>   ENTMAIN
              CLC                          ; 65816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              LDA   SHRXPIXEL
              SEC
              SBC   #$08                   ; Move to previous column
              CMP   SHRWINLFT
              BMI   :PREVLINE              ; x-pos < SHRWINLFT
              STA   SHRXPIXEL
              BRA   :DONE
:PREVLINE     LDA   SHRYPIXEL
              CLC                          ; Add 8 rows (go up)
              ADC   #$08
              CMP   SHRWINTOP
              BCS   :HOME                  ; y-pos >= SHRWINTOP
              STA   SHRYPIXEL
              LDA   SHRWINRGT
              SEC
              SBC   #$07
              STA   SHRXPIXEL
              BRA   :DONE
:HOME         LDA   SHRWINTOP
              STA   SHRYPIXEL
              LDA   SHRWINLFT
              STA   SHRXPIXEL
:DONE         SEC                          ; 65816 emulation mode
              XCE
              MX    %11                    ; Tell Merlin
              >>>   XF2AUX,VDUXXRET


* Handle cursor right in VDU5 mode
SHRVDU09      >>>   ENTMAIN
              CLC                          ; 65816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              LDA   SHRXPIXEL
              CLC
              ADC   #$08                   ; Advance to next column
              CMP   SHRWINRGT
              BCS   :NEWLINE               ; x-pos >= SHRWINRGT
              STA   SHRXPIXEL
              BRA   :DONE
:NEWLINE      LDA   SHRWINLFT
              STA   SHRXPIXEL
              JSR   SHRVDU5LF
:DONE         SEC                          ; 65816 emulation mode
              XCE
              MX    %11                    ; Tell Merlin
              >>>   XF2AUX,VDUXXRET


* Handle cursor down / linefeed in VDU5 mode
SHRVDU10      >>>   ENTMAIN
              CLC                          ; 65816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              JSR   SHRVDU5LF
:DONE         SEC                          ; 65816 emulation mode
              XCE
              MX    %11                    ; Tell Merlin
              >>>   XF2AUX,VDUXXRET


* Handle cursor up in VDU5 mode
SHRVDU11      >>>   ENTMAIN
              CLC                          ; 65816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              LDA   SHRYPIXEL
              CLC
              ADC   #$08                   ; Height of row of text
              CMP   SHRWINTOP
              BCS   :TOP                   ; y-pos >= SHRWINTOP
              STA   SHRYPIXEL
              BRA   :DONE
:TOP          LDA   SHRWINTOP
              STA   SHRYPIXEL
:DONE         SEC                          ; 65816 emulation mode
              XCE
              MX    %11                    ; Tell Merlin
              >>>   XF2AUX,VDUXXRET


* Handle linefeed in VDU5 mode - does the actual work
* Called in 65816 native mode, 16 bit M & X
SHRVDU5LF     MX    %00                    ; Tell Merlin
              LDA   SHRYPIXEL
              SEC
              SBC   #16                    ; Height of this+next row
              CMP   SHRWINBTM
              BCC   :NEWPAGE               ; Less than 16 rows left
              LDA   SHRYPIXEL
              SEC
              SBC   #$08
              STA   SHRYPIXEL
              BRA   :DONE
:NEWPAGE      LDA   SHRWINTOP
              STA   SHRYPIXEL
:DONE         RTS
              MX    %11                    ; 8 bit again


* Handle carriage return in VDU5 mode
SHRVDU13      >>>   ENTMAIN
              CLC                          ; 65816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              LDA   SHRWINLFT
              STA   SHRXPIXEL
:DONE         SEC                          ; 65816 emulation mode
              XCE
              MX    %11                    ; Tell Merlin
              >>>   XF2AUX,VDUXXRET


* Handle erasing char for VDU127 in VDU5 mode
* Called after SHRVDU08 has already backspaced cursor
SHRVDU127     >>>   ENTMAIN
              LDX   SHRYPIXEL              ; Screen row (Y-coord)
              LDA   SHRROWSL,X             ; Look up addr (LS byte)
              STA   A3L                    ; Stash in A3L
              LDA   SHRROWSH,X             ; Look up addr (MS byte)
              STA   A3H                    ; Stash in A3H
              LDA   #$E1                   ; Bank $E1
              STA   A4L
              LDX   SHRPIXELS
              CPX   #$02
              BNE   :MODE0
              CLC                          ; 65816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              LDA   SHRXPIXEL              ; Screen col (X-coord)
              LSR   A                      ; Divide by 2
              BRA   :MODE1
:MODE0        CLC                          ; 65816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              LDA   SHRXPIXEL              ; Screen col (X-coord)
              LSR   A                      ; Divide by 2
              LSR   A                      ; Divide by 4
              TAY
              LDX   #$00
              SEP   #$30                   ; 8 bit M & X
              MX    %11                    ; Tell Merlin
:L1           LDA   SHRGFXBGMASK
              STAL  [A3L],Y
              INY
              STAL  [A3L],Y
              DEY
              JSR   NEXTROW                ; Advance A3L/H to next pixel row
              INX
              CPX   #$08                   ; Erased all 8 rows?
              BNE   :L1
              BRA   :DONE
:MODE1        MX    %00                    ; Tell Merlin it's 16 bit M&X
              TAY
              LDX   #$00
              SEP   #$30                   ; 8 bit M & X
              MX    %11                    ; Tell Merlin
:L2           LDA   SHRGFXBGMASK
              STAL  [A3L],Y
              INY
              STAL  [A3L],Y
              INY
              STAL  [A3L],Y
              INY
              STAL  [A3L],Y
              DEY
              DEY
              DEY
              JSR   NEXTROW                ; Advance A3L/H to next pixel row
              INX
              CPX   #$08                   ; Erased all 8 rows?
              BNE   :L2
:DONE         SEC                          ; 65816 emulation mode
              XCE
              >>>   XF2AUX,VDUXXRET

* Advance A3L/H to next pixel row on screen
NEXTROW       LDA   A3L                    ; Advance A3L/H to next row
              CLC
              ADC   #160
              STA   A3L
              LDA   A3H
              ADC   #$00
              STA   A3H
              RTS

* Plot actions: PLOT k,x,y
* k is in SHRVDUQ+4
* x is in SHRVDUQ+5,SHRVDUQ+6
* y is in SHRVDUQ+7,SHRVDUQ+8
*
* Plot actions:
*  $00+x - move/draw lines     Where x: 0 - Move relative
*  $40+x - plot point                   1 - Draw relative FG
* [$50+x - fill triangle]               2 - Draw relative Inv FG
* [$60+x - fill rectangle]              3 - Draw relative BG
* [$90+x - draw circle]                 4 - Move absolute
* [$98+x - fill circle]                 5 - Draw abs FG
*                                       6 - Draw abs Inv FG
*                                       7 - Draw abs BG
* Note: abs/rel handled in auxmem.vdu.s
* TODO: No triangle filling or other fancy ops yet
SHRPLOT       >>>   ENTMAIN
              >>>   SHRCOORD               ; Convert coordinates
              LDA   A1L                    ; Preserve converted x
              PHA
              LDA   A1H
              PHA
              LDA   A2L                    ; Preserve converted y
              PHA
              LDA   A2H
              PHA
              LDA   SHRVDUQ+4              ; k
              AND   #$03
              CMP   #$00                   ; Bits 0,1 clear -> just move
              BEQ   :S2
              JSR   SHRPLOTCOL             ; Handle colour selection
              LDA   SHRVDUQ+4              ; k
              AND   #$F0                   ; Keep MS nybble
              CMP   #$00                   ; Move or draw line
              BNE   :S1
              JSR   SHRLINE
              BRA   :S2
:S1           CMP   #$40                   ; Plot point
              BNE   :BAIL                  ; Other? Bail out

*              PHP                          ; Disable interrupts
*              SEI
              CLC                          ; 65816 native mode
              XCE
              SEP   #$30                   ; 8 bit M & X
              MX    %11                    ; Tell Merlin
              JSR   SHRPOINT
              SEC                          ; 65816 emulation mode
              XCE
              MX    %11                    ; Tell Merlin
*              PLP                          ; Resume normal service

              BRA   :S2
:S2           PLA                          ; Store prev pt in screen coords
              STA   SHRYPIXEL+1
              PLA
              STA   SHRYPIXEL+0
              PLA
              STA   SHRXPIXEL+1
              PLA
              STA   SHRXPIXEL+0
:DONE         >>>   XF2AUX,GFXPLOTRET
:BAIL         PLA
              PLA
              PLA
              PLA
              LDA   SHRGFXFGMSK2           ; Restore original FG colour
              STA   SHRGFXFGMASK
              BRA   :DONE


* Handle colour selection for PLOT
SHRPLOTCOL    LDA   SHRGFXFGMASK           ; Preserve FG colour
              STA   SHRGFXFGMSK2
              LDA   SHRVDUQ+4              ; k
              AND   #$03
              CMP   #$02                   ; Inverse fFG
              BNE   :S1
              LDA   SHRGFXFGMASK           ; Load FG mask
              EOR   #$FF                   ; Negate / invert
              INC   A
              STA   SHRGFXFGMASK           ; Overwrite GF mask
              BRA   :DONE
:S1           CMP   #$03                   ; BG
              BNE   :DONE
              LDA   SHRGFXBGMASK           ; Load BG mask
              STA   SHRGFXFGMASK           ; Overwrite FG mask
:DONE         RTS


* Plot a point
* Called in 65816 native mode, 8 bit M & X
* On entry: A1L/H x-coordinate, A2L/H y-coordinate
SHRPOINT      REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              LDA   A2L                    ; y coordinate
              CMP   SHRWINBTM
              BMI   :OUT
              CMP   SHRWINTOP
              BEQ   :S1
              BPL   :OUT
:S1           LDA   A1L                    ; x coordinate
              CMP   SHRWINLFT
              BMI   :OUT
              CMP   SHRWINRGT
              BEQ   SHRPOINT2
              BPL   :OUT
              BRA   SHRPOINT2
:OUT          SEP   #$30                   ; 8 bit M & X
              MX    %11                    ; Tell Merlin
              RTS
SHRPOINT2     SEP   #$30                   ; 8 bit M & X
              MX    %11                    ; Tell Merlin

              LDX   A2L                    ; Screen row (Y-coord)
              LDA   SHRROWSL,X             ; Look up addr (LS byte)
              STA   A3L                    ; Stash in A3L
              LDA   SHRROWSH,X             ; Look up addr (MS byte)
              STA   A3H                    ; Stash in A3H
              LDA   #$E1                   ; Bank $E1
              STA   A4L

              LDX   A1L                    ; Store X-coord for later
              LSR   A1H                    ; Divide by 2
              ROR   A1L

              LDA   SHRPIXELS              ; Pixels per byte
              CMP   #$02                   ; 2 is 320-mode (MODE 1)
              BNE   :MODE0

              LDY   A1L                    ; Index into row of pixels
              TXA
              AND   #$01                   ; Keep LSB bit only
              TAX                          ; Index into :BITS320

              LDA   :BITS320,X             ; Get bit pattern for pixel to set
              BRA   SHRPLOTBYTE
              
:MODE0        LSR   A1H                    ; Divide X-coord by 2 again
              ROR   A1L
              LDY   A1L                    ; Index into row of pixels
              TXA
              AND   #$03                   ; Keep LSB two bits only
              TAX                          ; Index into :BITS640

              LDA   :BITS640,X             ; Get bit pattern for pixel to set

SHRPLOTBYTE   PHA
              LDA   SHRGFXACTION           ; GCOL action
              AND   #$0007                 ; Avoid table overflows
              ASL
              TAX
              PLA                          ; Recover bit pattern
              JMP   (:PLOTTBL, X)          ; Jump using jump table

:BITS320      DB    %11110000              ; Bit patterns for pixel ..
              DB    %00001111              ; .. within byte
:BITS640      DB    %11000000              ; Bit patterns for pixel ..
              DB    %00110000              ; .. within byte
              DB    %00001100
              DB    %00000011
:PLOTTBL      DW    SHRPLOTSET             ; Jump table for GCOL actions
              DW    SHRPLOTOR
              DW    SHRPLOTAND
              DW    SHRPLOTXOR
              DW    SHRPLOTNOT
              DW    SHRPLOTNOP
              DW    SHRPLOTCLR
              DW    SHRPLOTNOP


* Plot the specified colour (GCOL action 0)
* Pixel bit pattern in A
SHRPLOTSET    TAX                          ; Keep copy of bit pattern
              EOR   #$FF                   ; Invert bits
              AND   [A3L],Y                ; Load existing byte, clearing pixel
              STA   A1L
              TXA                          ; Get bit pattern back
              AND   SHRGFXFGMASK           ; Mask to set colour
              ORA   A1L                    ; OR into existing byte
              STA   [A3L],Y                ; Write to screen
              RTS


* OR with colour on screen (GCOL action 1)
* Pixel bit pattern in A
SHRPLOTOR     AND   SHRGFXFGMASK           ; Mask to set colour
              ORA   [A3L],Y                ; OR into existing byte
              STA   [A3L],Y                ; Write to screen
              RTS


* AND with colour on screen (GCOL action 2)
* Pixel bit pattern in A
SHRPLOTAND    TAX                          ; Keep copy of bit pattern
              AND   [A3L],Y                ; Mask bits to work on
              STA   A1L
              TXA                          ; Get bit pattern back
              AND   SHRGFXFGMASK           ; Mask to set colour
              AND   A1L                    ; AND with screen data
              STA   A1L
              TXA                          ; Get bit pattern back
              EOR   #$FF                   ; Invert
              AND   [A3L],Y                ; Mask remaining bits
              ORA   A1L                    ; Combine
              STA   [A3L],Y                ; Write to screen
              RTS


* XOR with colour on screen (GCOL action 3)
* Pixel bit pattern in A
SHRPLOTXOR    AND   SHRGFXFGMASK           ; Mask to set colour
              EOR   [A3L],Y                ; EOR into existing byte
              STA   [A3L],Y                ; Write to screen
              RTS


* NOT colour on screen (GCOL action 4)
* Pixel bit pattern in A
SHRPLOTNOT    TAX                          ; Keep copy of bit pattern
              STX   A1L
              LDA   [A3L],Y                ; Load existing byte
              EOR   #$FF                   ; Negate / invert existing byte
              AND   A1L                    ; Mask with bit pattern
              STA   A1L
              TXA                          ; Get bit pattern back
              EOR   #$FF                   ; Invert bits
              AND   [A3L],Y                ; Mask remaining bits
              ORA   A1L                    ; Combine
              STA   [A3L],Y                ; Write to screen
              RTS


* NO-OP (GCOL action 5)
* Pixel bit pattern in A
SHRPLOTNOP    RTS


* Clear (GCOL action 6)
* Pixel bit pattern in A, and also at top of stack
SHRPLOTCLR    EOR   #$FF                   ; Invert bits
              AND   [A3L],Y                ; Load existing byte, clearing pixel
              STA   [A3L],Y                ; Write to screen
              RTS


* Bresenham line drawing algorithm, entry point
* x0 is in SHRXPIXEL+0,SHRPIXEL+1
* y0 is in SHRYPIXEL
* x1 in A1L,A1H
* y1 in A2L
* Called in emulation mode.
* Uses TMPZP+0,+1
SHRLINE       LDA   A2L                    ; y1
              SEC
              SBC   SHRYPIXEL              ; Subtract y0
              BPL   :S1                    ; Skip if +ve
              EOR   #$FF                   ; Negate if -ve
              INC   A
:S1           STA   TMPZP+0                ; abs(y1 - y0)
              STZ   TMPZP+1                ; Pad to 16 bit
*              PHP                          ; Disable interrupts
*              SEI
              CLC                          ; 65816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              LDA   A1L                    ; Load x1 (A1L,A1H)
              SEC
              SBC   SHRXPIXEL              ; Subtract x0
              BPL   :S2                    ; Skip if +ve
              EOR   #$FFFF                 ; Negate if -ve
              INC   A
:S2           CMP   TMPZP                  ; Cmp abs(x1 - x0) w/ abs(y1 - y0)
              BCC   :YDOM                  ; abs(x1 - x0) < abs(y1 - y0)

:XDOM         LDA   SHRXPIXEL              ; x0
              CMP   A1L                    ; x1
              BPL   :X1                    ; x0 >= x1
              JMP   SHRLINELO              ; x0 < x1
:X1           JSR   SHRLINESWAP            ; Swap parms
              JMP   SHRLINELO

:YDOM         LDA   SHRYPIXEL              ; y0
              CMP   A2L                    ; y1
              BPL   :Y1                    ; y0 >= y1
              JMP   SHRLINEHI              ; y0 < y1
:Y1           JSR   SHRLINESWAP            ; Swap parms
              JMP   SHRLINEHI


* Swap (x0, y0) and (x1, y1)
* Called in 65816 native mode, 16 bit M &X
* Uses TMPZP+0,+1
SHRLINESWAP   LDA   SHRXPIXEL              ; x0
              STA   TMPZP
              LDA   A1L                    ; x1
              STA   SHRXPIXEL
              LDA   TMPZP
              STA   A1L
              LDA   SHRYPIXEL              ; y0
              STA   TMPZP
              LDA   A2L                    ; y1
              STA   SHRYPIXEL
              LDA   TMPZP
              STA   A2L
              RTS


* Plot x-dominant line (shallow gradient)
* Called in 65816 native mode, 16 bit M & X. Returns in emulation mode.
SHRLINELO     MX    %00                    ; Tell merlin 16 bit M & X
              LDA   A1L                    ; x1
              STA   :LIM                   ; We re-use A1L/H later
              SEC
              SBC   SHRXPIXEL              ; Subtract x0
              STA   :DX
              LDA   A2L                    ; y1
              SEC
              SBC   SHRYPIXEL              ; Subtract y0
              STA   :DY
              LDA   #$0001
              STA   :YI                    ; yi = 1

              LDA   :DY
              BPL   :S1                    ; Skip if dy = 0
              LDA   #$FFFF
              STA   :YI                    ; yi = -1
              EOR   :DY                    ; Negate dy
              INC   A
              STA   :DY                    ; dy = -dy

:S1           TAY                          ; dy
              ASL                          ; 2 * dy
              STA   :DY                    ; DY now (2 * dy)
              SEC
              SBC   :DX                    ; (2 * dy) - dx
              STA   :D                     ; D = (2 * dy) - dx
              LDA   SHRYPIXEL              ; y0
              STA   A2L                    ; y = y0 (re-using A2L/H)
              TYA
              SEC
              SBC   :DX
              ASL
              STA   :DX                    ; DX now (2 * (dy - dx)

              LDX   SHRXPIXEL              ; x = x0
:L1           STX   A1L                    ; Store x-coord for SHRPOINT
              PHX
              SEP   #$30                   ; 8 bit M & X
              MX    %11                    ; Tell Merlin
              JSR   SHRPOINT               ; x in A1L/H, y in A2L
              REP   #$31                   ; 16 bit M & X, CLC
              MX    %00                    ; Tell Merlin
              PLX
              LDA   :D
              BMI   :S2                    ; D < 0
              ADC   :DX
              STA   :D                     ; D = D + (2 * (dy - dx))
              LDA   A2L                    ; y
              CLC                          ; (Required)
              ADC   :YI
              STA   A2L                    ; y = y + yi
              BRA   :S3
:S2         ; CLC                          ; Already CC
              ADC   :DY
              STA   :D                     ; D = D + 2 * dy
:S3           INX
              CPX   :LIM                   ; Compare with x1
              BNE   :L1

              SEC                          ; 65816 emulation mode
              XCE
              MX    %11                    ; Tell Merlin
*              PLP                          ; Resume normal service
              RTS
* Zero page
:DX           EQU   TMPZP+0                ; dx initially, then (2 * (dy - dx))
:DY           EQU   TMPZP+2                ; dy initially, then (2 * dy)
:YI           EQU   TMPZP+4                ; +1 or -1
:D            EQU   TMPZP+6                ; D
:LIM          EQU   TMPZP+8                ; x1 gets stashed here


* Plot y-dominant line (steep gradient)
* Called in 65816 native mode, 16 bit M & X. Returns in emulation mode.
SHRLINEHI     MX    %00                    ; Tell Merlin 16 bit M & X
              LDA   A1L                    ; x1
              SEC
              SBC   SHRXPIXEL              ; Subtract x0
              STA   :DX
              LDA   A2L                    ; y1
              STA   :LIM                   ; We re-use A1L/H later
              SEC
              SBC   SHRYPIXEL              ; Subtract y0
              STA   :DY
              LDA   #$0001
              STA   :XI                    ; xi = 1

              LDA   :DX
              BPL   :S1                    ; Skip if dx = 0
              LDA   #$FFFF
              STA   :XI                    ; xi = -1
              EOR   :DX                    ; Negate dx
              INC   A
              STA   :DX                    ; dx = -dx

:S1           TAX                          ; dx
              ASL                          ; 2 * dx
              STA   :DX                    ; DX now (2 * dx)
              SEC
              SBC   :DY                    ; (2 * dx) - dy
              STA   :D                     ; D = (2 * dx) - dy
              LDA   SHRXPIXEL              ; x0
              STA   :X                     ; x = x0
              TXA
              SEC
              SBC   :DY
              ASL
              STA   :DY                    ; DY now (2 * (dx - dy)

              LDX   SHRYPIXEL              ; y = y0
:L1           LDA   :X
              STA   A1L                    ; Store x-coord for SHRPOINT
              STX   A2L                    ; Store y-coord for SHRPOINT
              PHX
              SEP   #$30                   ; 8 bit M & X
              MX    %11                    ; Tell Merlin
              JSR   SHRPOINT               ; x in A1L/H, y in A2L
              REP   #$31                   ; 16 bit M & X, CLC
              MX    %00                    ; Tell Merlin
              PLX
              LDA   :D
              BMI   :S2                    ; D < 0
              ADC   :DY
              STA   :D                     ; D = D + (2 * (dx - dy))
              LDA   :X                     ; x
              CLC                          ; (Required)
              ADC   :XI
              STA   :X                     ; x = x + xi
              BRA   :S3
:S2         ; CLC                          ; Already CC
              ADC   :DX
              STA   :D                     ; D = D + 2 * dx
:S3           INX
              CPX   :LIM                   ; Compare with y1
              BNE   :L1

              SEC                          ; 65816 emulation mode
              XCE
              MX    %11                    ; Tell Merlin
*              PLP                          ; Resume normal service
              RTS
* Zero page
:X            EQU   TMPZP+0
:DX           EQU   TMPZP+2                ; dx initially, then (2 * dx)
:DY           EQU   TMPZP+4                ; dy initially, then (2 * (dx - dy)))
:XI           EQU   TMPZP+6                ; +1 or -1
:D            EQU   TMPZP+8                ; D
:LIM          EQU   TMPZP+10               ; x1 gets stashed here


* Macro to convert high-resolution screen coordinates
* from 1280x1024 to 640x200 or 320x200
* On return: X-coordinate in A1L/H, Y-coordinate in A2L (A2H=0)
SHRCOORD      MAC
*              PHP                          ; Disable interrupts
*              SEI
              CLC                          ; 65816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin

* X-coordinate in SHRVDUQ+5,+6   1280/2=640 or 1280/4=320
              LDA   SHRVDUQ+5
              ASL                          ; Sign bit -> C
              ROR   SHRVDUQ+5              ; Signed divide /2

              LDA   SHRPIXELS              ; Pixels per byte
              AND   #$00FF                 ; Mask
              CMP   #$02                   ; 2 is 320-mode (MODE 1)
              BNE   SHRCOORDM0
              LDA   SHRVDUQ+5
              ASL                          ; Sign bit -> C
              ROR   SHRVDUQ+5              ; Signed divide /2
SHRCOORDM0    LDA   SHRVDUQ+5
              STA   A1L                    ; Result in A1L/H

* Y-coordinate in SHRVDUQ+7,+8   1024*25/128=200
              LDA   SHRVDUQ+7
              BMI   SHRCOORDNEG
              ASL                          ; *2
              ADC   SHRVDUQ+7              ; *3
              ASL                          ; *6
              ASL                          ; *12
              ASL                          ; *24
              ADC   SHRVDUQ+7              ; *25

* Clever speedup trick thanks to Kent Dickey @ A2Infinitum
* now we have valid data in acc[15:7], and we want to shift right 7 bits to
* get acc[8:0] as the valid bits.  If we left shift one bit and xba,
* we get acc[7:0] in the proper bits, so we just have to bring the bit we
* just shifted out back
* See: https://apple2infinitum.slack.com/archives/CA8AT5886/p1628877444215300
* for code on how to shift left 7 bits

              ASL                          ;
              AND   #$FF00                 ; Mask bits
              ADC   #0                     ; Add in carry (9th bit)
              XBA                          ; Clever trick: fewer shifts
              STA   A2L                    ; Into A2L/H
        
              SEC                          ; Back to emulation mode
              XCE
              MX    %11                    ; Tell Merlin
*              PLP                          ; Normal service resumed
              BRA   SHRCOORDEND

SHRCOORDNEG   MX    %00                    ; Tell Merlin we are 16 bit
              EOR   #$FFFF                 ; Negate
              INC   A
              ASL                          ; *2
              ADC   SHRVDUQ+7              ; *3
              ASL                          ; *6
              ASL                          ; *12
              ASL                          ; *24
              ADC   SHRVDUQ+7              ; *25

* Clever speedup trick thanks to Kent Dickey @ A2Infinitum
* now we have valid data in acc[15:7], and we want to shift right 7 bits to
* get acc[8:0] as the valid bits.  If we left shift one bit and xba,
* we get acc[7:0] in the proper bits, so we just have to bring the bit we
* just shifted out back
* See: https://apple2infinitum.slack.com/archives/CA8AT5886/p1628877444215300
* for code on how to shift left 7 bits

              ASL                          ;
              AND   #$FF00                 ; Mask bits
              ADC   #0                     ; Add in carry (9th bit)
              XBA                          ; Clever trick: fewer shifts
              EOR   #$FFFF                 ; Negate
              INC   A
              STA   A2L                    ; Into A2L/H
        
              SEC                          ; Back to emulation mode
              XCE
              MX    %11                    ; Tell Merlin
*              PLP                          ; Normal service resumed
SHRCOORDEND   EOM


* Another coordinate transform, used by VDU25
* Same as SHRCOORD above, except it is entered in native, 16 bit M & X mode
* Assumes positive coordinates.
* On entry: X is offset into SHRVDUQ to find coordinate
* On return: Coverted coordinats in A1L/H, A2L/H
SHRCOORD2     MX    $00                    ; Tell Merlin it's 16 bit

* X-coordinate in SHRVDUQ+5,+6   1280/2=640
              LSR   SHRVDUQ,X              ; Unsigned divide /2
              LDA   SHRPIXELS              ; Pixels per byte
              AND   #$00FF                 ; Mask
              CMP   #$02                   ; 2 is 320-mode (MODE 1)
              BNE   SHRCOORD2M0
              LSR   SHRVDUQ,X              ; Unsigned divide /2 again
SHRCOORD2M0   LDA   SHRVDUQ,X
              STA   A1L                    ; Result in A1L/H

* Y-coordinate in SHRVDUQ+7,+8   1024*25/128=200
              LDA   SHRVDUQ+2,X
              ASL                          ; *2
              ADC   SHRVDUQ+2,X            ; *3
              ASL                          ; *6
              ASL                          ; *12
              ASL                          ; *24
              ADC   SHRVDUQ+2,X            ; *25

              ASL                          ;
              AND   #$FF00                 ; Mask bits
              ADC   #0                     ; Add in carry (9th bit)
              XBA                          ; Clever trick: fewer shifts
              STA   A2L                    ; Into A2L/H
              RTS


              MX    %11                    ; Following code is 8 bit again


* Clear the graphics window
SHRVDU16      >>>   ENTMAIN
*              PHP                          ; Disable interrupts
*              SEI
              CLC                          ; 816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              INC   SHRWINTOP
              INC   SHRWINRGT
              LDX   SHRWINBTM

              LDA   SHRPIXELS
              AND   #$00FF
              CMP   #$02
              BNE   :M0                    ; MODE0

              LDA   SHRWINLFT
              LSR   A                      ; Divide left by 2
              INC   A                      ; Treat left column specially
              STA   :LEFTLIM
              LDA   SHRWINRGT
              LSR   A                      ; Divide right by 2
              STA   :RIGHTLIM
              BRA   :S0

:M0           LDA   SHRWINLFT
              LSR   A                      ; Divide left by 4
              LSR   A
              INC   A                      ; Treat left column specially
              STA   :LEFTLIM
              LDA   SHRWINRGT
              LSR   A                      ; Divide right by 4
              LSR   A
              STA   :RIGHTLIM
              BRA   :S0

:S0           SEP   #$30                   ; 8 bit M & X
              MX    %11                    ; Tell Merlin
:L1           LDY   :LEFTLIM
              LDA   SHRROWSL,X             ; Look up addr (LS byte)
              STA   A3L                    ; Stash in A3L
              LDA   SHRROWSH,X             ; Look up addr (MS byte)
              STA   A3H                    ; Stash in A3H
              LDA   #$E1                   ; Bank $E1
              STA   A4L

              LDA   SHRGFXBGMASK
:L2           CPY   :RIGHTLIM
              BCS   :S1
              STA   [A3L],Y
              INY
              CPY   :RIGHTLIM
              BRA   :L2

:S1           INX
              CPX   SHRWINTOP
              BNE   :L1

              LDA   SHRPIXELS
              CMP   #$02
              BNE   :MODE0

              LDA   SHRWINRGT
              AND   #$01
              TAX
              LDA   :RIGHT320,X            ; Bits to set
              JSR   SHRVDU16V              ; Handle right edge

              LDY   :LEFTLIM
              DEY                          ; Handle leftmost byte
              LDA   SHRWINLFT
              AND   #$01
              TAX
              LDA   :LEFT320,X             ; Bits to set
              JSR   SHRVDU16V              ; Handle left edge
              BRA   :DONE

:MODE0        LDA   SHRWINRGT
              AND   #$03
              TAX
              LDA   :RIGHT640,X            ; Bits to set
              JSR   SHRVDU16V              ; Handle right edge

              LDY   :LEFTLIM
              DEY                          ; Handle leftmost byte
              LDA   SHRWINLFT
              AND   #$03
              TAX
              LDA   :LEFT640,X             ; Bits to set
              JSR   SHRVDU16V              ; Handle left edge

:DONE         REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              DEC   SHRWINTOP
              DEC   SHRWINRGT

              SEC                          ; Back to 6502 emu mode
              XCE
              MX    %11                    ; Tell Merlin
*              PLP                          ; Normal service resumed
              >>>   XF2AUX,SHRCLRRET
:LEFT320      DB    %11111111
              DB    %00001111
:LEFT640      DB    %11111111
              DB    %00111111
              DB    %00001111
              DB    %00000011
:RIGHT320     DB    %00000000
              DB    %11110000
:RIGHT640     DB    %00000000
              DB    %11000000
              DB    %11110000
              DB    %11111100
* Zero page
:LEFTLIM      EQU   TMPZP+0                ; 2 bytes of ZP
:RIGHTLIM     EQU   TMPZP+2                ; 2 bytes of ZP


* Helper routine to draw vertical lines
* Draw line from A1L,SHRWINBTM to A1L,SHRWINBTM in BG colour
* Called in 65816 native mode, 8 bit M & X
* On entry: Y - byte offset into row, A - bit pattern to set
SHRVDU16V     PHA
              LDX   SHRWINBTM
:L1           LDA   SHRROWSL,X             ; Look up addr (LS byte)
              STA   A3L                    ; Stash in A3L
              LDA   SHRROWSH,X             ; Look up addr (MS byte)
              STA   A3H                    ; Stash in A3H
              LDA   #$E1                   ; Bank $E1
              STA   A4L

              PLA
              PHA
              EOR   #$FF                   ; Invert bits
              AND   [A3L],Y                ; Load existing byte, clearing pixel
              STA   A1L
              PLA
              PHA
              AND   SHRGFXBGMASK           ; Mask to set colour
              ORA   A1L                    ; OR into existing byte
              STA   [A3L],Y                ; Write to screen

              INX
              CPX   SHRWINTOP
              BNE   :L1
              PLA
              RTS


* Validate graphics window parms & store if okay
* First 8 bytes of SHRVDUQ: left, bottom, right, top
SHRVDU24      >>>   ENTMAIN
*              PHP                          ; Disable interrupts
*              SEI
              CLC                          ; 65816 native mode
              XCE
              REP   #$30                   ; 16 bit M & X
              MX    %00                    ; Tell Merlin
              LDA   SHRVDUQ+4              ; Right
              CMP   SHRVDUQ+0              ; Left
              BCC   :BAD                   ; right<left
              CMP   #1280                  ; width
              BCS   :BAD                   ; right>=width
              LDA   SHRVDUQ+6              ; Top
              CMP   SHRVDUQ+2              ; Bottom
              BCC   :BAD                   ; top<bottom
              CMP   #1024                  ; height
              BCS   :BAD                   ; top>=height
             
              LDX   #$00                   ; Start of SHRVDUQ 
              JSR   SHRCOORD2              ; Convert left, bottom
              LDA   A1L                    ; left converted
              STA   SHRWINLFT
              LDA   A2L                    ; bottom converted
              STA   SHRWINBTM
              LDX   #$04                   ; 4 byte offset
              JSR   SHRCOORD2              ; Convert right, top
              LDA   A1L                    ; right converted
              STA   SHRWINRGT
              LDA   A2L                    ; top converted
              STA   SHRWINTOP

              SEC                          ; 65816 emulation mode
              XCE
*              PLP
              >>>   XF2AUX,VDU24RET
:BAD          SEC                          ; 65816 emulation mode
              XCE
*              PLP
              >>>   XF2AUX,VDUXXRET


* Reset graphics window
* Initialize other locals (called on MODE)
SHRVDU26      >>>   ENTMAIN

              STZ   SHRWINLFT+0            ; Graphics window
              STZ   SHRWINLFT+1
              STZ   SHRWINBTM+0
              STZ   SHRWINBTM+1
              LDY   SHRPIXELS
              CPY   #$02
              BNE   :MODE0
              LDA   #<319
              STA   SHRWINRGT+0
              LDA   #>319
              STA   SHRWINRGT+1
              BRA   :S1
:MODE0        LDA   #<639
              STA   SHRWINRGT+0
              LDA   #>639
              STA   SHRWINRGT+1
:S1           LDA   #<199
              STA   SHRWINTOP+0
              LDA   #>199
              STA   SHRWINTOP+1

              STZ   SHRXPIXEL+0            ; Other locals
              STZ   SHRXPIXEL+1
              STZ   SHRYPIXEL+0
              STZ   SHRYPIXEL+1

              >>>   XF2AUX,VDU26RET


* Set up default palette
SHRDEFPALM    >>>   ENTMAIN
              LDY   #00                    ; Palette offset for 320 mode
              LDA   SHRPIXELS              ; Pixels per byte
              CMP   #$02                   ; 2 is 320-mode (MODE 1)
              BEQ   :S1
              LDY   #32                    ; Palette offset for 640 mode
:S1           LDX   #$00
:L1           LDA   PALETTE320,Y           ; Offset in Y computed above
              STAL  $E19E00,X              ; Palettes begin at $9E00 in $E1
              INX
              INY
              CPX   #32                    ; 32 bytes in palette
              BNE   :L1
              >>>   XF2AUX,SHRDEFPALRET


* Assign a 'physical' colour from the 16 colour palette to a
* 'logical' colour for the current mode
* On entry: A=logical colour, Y=physical colour
SHRPALCHANGE  >>>   ENTMAIN
              TAX
              TYA
              AND   #%00011110             ; Has already been shifted
              TAY
              LDA   SHRPIXELS              ; Pixels per byte
              CMP   #$02                   ; 2 is 320-mode (MODE 1)
              BEQ   :MODE320
              TXA
              AND   #%00000110             ; Has already been shifted
              TAX
              LDA   PALETTE320,Y           ; Byte 1 of physical colour
              STAL  $E19E00,X              ; Store in logical slot (4 copies)
              STAL  $E19E00+8,X
              STAL  $E19E00+16,X
              STAL  $E19E00+24,X
              LDA   PALETTE320+1,Y         ; Byte 2 of physical colour
              STAL  $E19E00+1,X            ; Store in logical slot (4 copies)
              STAL  $E19E00+9,X
              STAL  $E19E00+17,X
              STAL  $E19E00+25,X
              RTS
:MODE320      TXA
              AND   #%00011110             ; Has already been shifted
              TAX
              LDA   PALETTE320,Y           ; Byte 1 of physical colour
              STAL  $E19E00,X              ; Store in logical slot
              LDA   PALETTE320+1,Y         ; Byte 2 of physical colour
              STAL  $E19E00+1,X            ; Store in logical slot
              >>>   XF2AUX,VDUXXRET 


* Assign a custom RGB colour to a 'logical' colour
* On entry: A=GB components, Y=R component, SHRVDUQ=logical colour
SHRPALCUSTOM  >>>   ENTMAIN
              LDX   SHRVDUQ
              PHA                          ; Preserve GB components
              LDA   SHRPIXELS              ; Pixels per byte
              CMP   #$02                   ; 2 is 320-mode (MODE 1)
              BEQ   :MODE320
              TXA
              AND   #%00000110             ; Has already been shifted
              TAX
              PLA                          ; Recover GB components
              STAL  $E19E00,X              ; Store in logical slot (4 copies)
              STAL  $E19E00+8,X
              STAL  $E19E00+16,X
              STAL  $E19E00+24,X
              TYA                          ; R component
              STAL  $E19E00+1,X            ; Store in logical slot (4 copies)
              STAL  $E19E00+9,X
              STAL  $E19E00+17,X
              STAL  $E19E00+25,X
              RTS
:MODE320      TXA
              AND   #%00011110             ; Has already been shifted
              TAX
              PLA                          ; Recover GB components
              STAL  $E19E00,X              ; Store in logical slot
              TYA                          ; R component
              STAL  $E19E00+1,X            ; Store in logical slot
              >>>   XF2AUX,VDUXXRET 
              

* Table of addresses of SHR rows (in reverse order)
SHRROWSL      DB    <$9c60
              DB    <$9bc0
              DB    <$9b20
              DB    <$9a80
              DB    <$99e0
              DB    <$9940
              DB    <$98a0
              DB    <$9800
              DB    <$9760
              DB    <$96c0
              DB    <$9620
              DB    <$9580
              DB    <$94e0
              DB    <$9440
              DB    <$93a0
              DB    <$9300
              DB    <$9260
              DB    <$91c0
              DB    <$9120
              DB    <$9080
              DB    <$8fe0
              DB    <$8f40
              DB    <$8ea0
              DB    <$8e00
              DB    <$8d60
              DB    <$8cc0
              DB    <$8c20
              DB    <$8b80
              DB    <$8ae0
              DB    <$8a40
              DB    <$89a0
              DB    <$8900
              DB    <$8860
              DB    <$87c0
              DB    <$8720
              DB    <$8680
              DB    <$85e0
              DB    <$8540
              DB    <$84a0
              DB    <$8400
              DB    <$8360
              DB    <$82c0
              DB    <$8220
              DB    <$8180
              DB    <$80e0
              DB    <$8040
              DB    <$7fa0
              DB    <$7f00
              DB    <$7e60
              DB    <$7dc0
              DB    <$7d20
              DB    <$7c80
              DB    <$7be0
              DB    <$7b40
              DB    <$7aa0
              DB    <$7a00
              DB    <$7960
              DB    <$78c0
              DB    <$7820
              DB    <$7780
              DB    <$76e0
              DB    <$7640
              DB    <$75a0
              DB    <$7500
              DB    <$7460
              DB    <$73c0
              DB    <$7320
              DB    <$7280
              DB    <$71e0
              DB    <$7140
              DB    <$70a0
              DB    <$7000
              DB    <$6f60
              DB    <$6ec0
              DB    <$6e20
              DB    <$6d80
              DB    <$6ce0
              DB    <$6c40
              DB    <$6ba0
              DB    <$6b00
              DB    <$6a60
              DB    <$69c0
              DB    <$6920
              DB    <$6880
              DB    <$67e0
              DB    <$6740
              DB    <$66a0
              DB    <$6600
              DB    <$6560
              DB    <$64c0
              DB    <$6420
              DB    <$6380
              DB    <$62e0
              DB    <$6240
              DB    <$61a0
              DB    <$6100
              DB    <$6060
              DB    <$5fc0
              DB    <$5f20
              DB    <$5e80
              DB    <$5de0
              DB    <$5d40
              DB    <$5ca0
              DB    <$5c00
              DB    <$5b60
              DB    <$5ac0
              DB    <$5a20
              DB    <$5980
              DB    <$58e0
              DB    <$5840
              DB    <$57a0
              DB    <$5700
              DB    <$5660
              DB    <$55c0
              DB    <$5520
              DB    <$5480
              DB    <$53e0
              DB    <$5340
              DB    <$52a0
              DB    <$5200
              DB    <$5160
              DB    <$50c0
              DB    <$5020
              DB    <$4f80
              DB    <$4ee0
              DB    <$4e40
              DB    <$4da0
              DB    <$4d00
              DB    <$4c60
              DB    <$4bc0
              DB    <$4b20
              DB    <$4a80
              DB    <$49e0
              DB    <$4940
              DB    <$48a0
              DB    <$4800
              DB    <$4760
              DB    <$46c0
              DB    <$4620
              DB    <$4580
              DB    <$44e0
              DB    <$4440
              DB    <$43a0
              DB    <$4300
              DB    <$4260
              DB    <$41c0
              DB    <$4120
              DB    <$4080
              DB    <$3fe0
              DB    <$3f40
              DB    <$3ea0
              DB    <$3e00
              DB    <$3d60
              DB    <$3cc0
              DB    <$3c20
              DB    <$3b80
              DB    <$3ae0
              DB    <$3a40
              DB    <$39a0
              DB    <$3900
              DB    <$3860
              DB    <$37c0
              DB    <$3720
              DB    <$3680
              DB    <$35e0
              DB    <$3540
              DB    <$34a0
              DB    <$3400
              DB    <$3360
              DB    <$32c0
              DB    <$3220
              DB    <$3180
              DB    <$30e0
              DB    <$3040
              DB    <$2fa0
              DB    <$2f00
              DB    <$2e60
              DB    <$2dc0
              DB    <$2d20
              DB    <$2c80
              DB    <$2be0
              DB    <$2b40
              DB    <$2aa0
              DB    <$2a00
              DB    <$2960
              DB    <$28c0
              DB    <$2820
              DB    <$2780
              DB    <$26e0
              DB    <$2640
              DB    <$25a0
              DB    <$2500
              DB    <$2460
              DB    <$23c0
              DB    <$2320
              DB    <$2280
              DB    <$21e0
              DB    <$2140
              DB    <$20a0
              DB    <$2000

SHRROWSH      DB    >$9c60
              DB    >$9bc0
              DB    >$9b20
              DB    >$9a80
              DB    >$99e0
              DB    >$9940
              DB    >$98a0
              DB    >$9800
              DB    >$9760
              DB    >$96c0
              DB    >$9620
              DB    >$9580
              DB    >$94e0
              DB    >$9440
              DB    >$93a0
              DB    >$9300
              DB    >$9260
              DB    >$91c0
              DB    >$9120
              DB    >$9080
              DB    >$8fe0
              DB    >$8f40
              DB    >$8ea0
              DB    >$8e00
              DB    >$8d60
              DB    >$8cc0
              DB    >$8c20
              DB    >$8b80
              DB    >$8ae0
              DB    >$8a40
              DB    >$89a0
              DB    >$8900
              DB    >$8860
              DB    >$87c0
              DB    >$8720
              DB    >$8680
              DB    >$85e0
              DB    >$8540
              DB    >$84a0
              DB    >$8400
              DB    >$8360
              DB    >$82c0
              DB    >$8220
              DB    >$8180
              DB    >$80e0
              DB    >$8040
              DB    >$7fa0
              DB    >$7f00
              DB    >$7e60
              DB    >$7dc0
              DB    >$7d20
              DB    >$7c80
              DB    >$7be0
              DB    >$7b40
              DB    >$7aa0
              DB    >$7a00
              DB    >$7960
              DB    >$78c0
              DB    >$7820
              DB    >$7780
              DB    >$76e0
              DB    >$7640
              DB    >$75a0
              DB    >$7500
              DB    >$7460
              DB    >$73c0
              DB    >$7320
              DB    >$7280
              DB    >$71e0
              DB    >$7140
              DB    >$70a0
              DB    >$7000
              DB    >$6f60
              DB    >$6ec0
              DB    >$6e20
              DB    >$6d80
              DB    >$6ce0
              DB    >$6c40
              DB    >$6ba0
              DB    >$6b00
              DB    >$6a60
              DB    >$69c0
              DB    >$6920
              DB    >$6880
              DB    >$67e0
              DB    >$6740
              DB    >$66a0
              DB    >$6600
              DB    >$6560
              DB    >$64c0
              DB    >$6420
              DB    >$6380
              DB    >$62e0
              DB    >$6240
              DB    >$61a0
              DB    >$6100
              DB    >$6060
              DB    >$5fc0
              DB    >$5f20
              DB    >$5e80
              DB    >$5de0
              DB    >$5d40
              DB    >$5ca0
              DB    >$5c00
              DB    >$5b60
              DB    >$5ac0
              DB    >$5a20
              DB    >$5980
              DB    >$58e0
              DB    >$5840
              DB    >$57a0
              DB    >$5700
              DB    >$5660
              DB    >$55c0
              DB    >$5520
              DB    >$5480
              DB    >$53e0
              DB    >$5340
              DB    >$52a0
              DB    >$5200
              DB    >$5160
              DB    >$50c0
              DB    >$5020
              DB    >$4f80
              DB    >$4ee0
              DB    >$4e40
              DB    >$4da0
              DB    >$4d00
              DB    >$4c60
              DB    >$4bc0
              DB    >$4b20
              DB    >$4a80
              DB    >$49e0
              DB    >$4940
              DB    >$48a0
              DB    >$4800
              DB    >$4760
              DB    >$46c0
              DB    >$4620
              DB    >$4580
              DB    >$44e0
              DB    >$4440
              DB    >$43a0
              DB    >$4300
              DB    >$4260
              DB    >$41c0
              DB    >$4120
              DB    >$4080
              DB    >$3fe0
              DB    >$3f40
              DB    >$3ea0
              DB    >$3e00
              DB    >$3d60
              DB    >$3cc0
              DB    >$3c20
              DB    >$3b80
              DB    >$3ae0
              DB    >$3a40
              DB    >$39a0
              DB    >$3900
              DB    >$3860
              DB    >$37c0
              DB    >$3720
              DB    >$3680
              DB    >$35e0
              DB    >$3540
              DB    >$34a0
              DB    >$3400
              DB    >$3360
              DB    >$32c0
              DB    >$3220
              DB    >$3180
              DB    >$30e0
              DB    >$3040
              DB    >$2fa0
              DB    >$2f00
              DB    >$2e60
              DB    >$2dc0
              DB    >$2d20
              DB    >$2c80
              DB    >$2be0
              DB    >$2b40
              DB    >$2aa0
              DB    >$2a00
              DB    >$2960
              DB    >$28c0
              DB    >$2820
              DB    >$2780
              DB    >$26e0
              DB    >$2640
              DB    >$25a0
              DB    >$2500
              DB    >$2460
              DB    >$23c0
              DB    >$2320
              DB    >$2280
              DB    >$21e0
              DB    >$2140
              DB    >$20a0
              DB    >$2000


