BBC Micro Elite

# Drawing lines: LOIN (Part 4 of 7) (6502SP version)

```       Name: LOIN (Part 4 of 7)                                [View in context]
Type: Subroutine
Category: Drawing lines
Summary: Draw a shallow line going right and down or left and up

This routine draws a line from (X1, Y1) to (X2, Y2). It has multiple stages.
If we get here, then:

* The line is going right and down (no swap) or left and up (swap)

* X1 < X2 and Y1 <= Y2

* Draw from (X1, Y1) at top left to (X2, Y2) at bottom right

This routine looks complex, but that's because the loop that's used in the
cassette and disc versions has been unrolled to speed it up. The algorithm is
unchanged, it's just a lot longer.

.DOWN

LDA #%10001000         \ Modify the value in the LDA instruction at LI200 below
AND COL                \ to contain a pixel mask for the first pixel in the
STA LI200+1            \ 4-pixel byte, in the colour COL, so that it draws in
\ the correct colour

LDA #%01000100         \ Modify the value in the LDA instruction at LI210 below
AND COL                \ to contain a pixel mask for the second pixel in the
STA LI210+1            \ 4-pixel byte, in the colour COL, so that it draws in
\ the correct colour

LDA #%00100010         \ Modify the value in the LDA instruction at LI220 below
AND COL                \ to contain a pixel mask for the third pixel in the
STA LI220+1            \ 4-pixel byte, in the colour COL, so that it draws in
\ the correct colour

LDA #%00010001         \ Modify the value in the LDA instruction at LI230 below
AND COL                \ to contain a pixel mask for the fourth pixel in the
STA LI230+1            \ 4-pixel byte, in the colour COL, so that it draws in
\ the correct colour

LDA SC                 \ Set SC(1 0) = SC(1 0) - 248
SBC #248
STA SC
LDA SC+1
SBC #0
STA SC+1

TYA                    \ Set bits 3-7 of Y, which contains the pixel row within
EOR #%11111000         \ the character, and is therefore in the range 0-7, so
TAY                    \ this does Y = 248 + Y
\
\ We therefore have the following:
\
\   SC(1 0) + Y = SC(1 0) - 248 + 248 + Y
\               = SC(1 0) + Y
\
\ so the screen location we poke hasn't changed, but Y
\ is now a larger number and SC is smaller. This means
\ we can increment Y to move down a line, as per usual,
\ but we can test for when it reaches the bottom of the
\ character block with a simple BEQ rather than checking
\ whether it's reached 8, so this appears to be a code
\ optimisation

\ We now work our way along the line from left to right,
\ using X as a decreasing counter, and at each count we
\ plot a single pixel using the pixel mask in R

LDA SWAP               \ If SWAP = 0 then we didn't swap the coordinates above,
BEQ LI191              \ so jump down to LI191 to plot the first pixel

\ If we get here then we want to omit the first pixel

LDA R                  \ Fetch the pixel byte from R, which we set in part 2 to
\ the horizontal pixel number within the character block
\ where the line starts (so it's 0, 1, 2 or 3)

BEQ LI200+6            \ If R = 0, jump to LI200+6 to start plotting from the
\ second pixel in this byte (LI200+6 points to the DEX
\ instruction after the EOR/STA instructions, so the
\ pixel doesn't get plotted but we join at the right
\ point to decrement X correctly to plot the next three)

CMP #2                 \ If R < 2 (i.e. R = 1), jump to LI210+6 to skip the
BCC LI210+6            \ first two pixels but plot the next two

CLC                    \ Clear the C flag so it doesn't affect the additions
\ below

BEQ LI220+6            \ If R = 2, jump to LI220+6 to to skip the first three
\ pixels but plot the last one

BNE LI230+6            \ If we get here then R must be 3, so jump to LI230+6 to
\ skip plotting any of the pixels, but making sure we
\ join the routine just after the plotting instructions

.LI191

DEX                    \ Decrement the counter in X because we're about to plot
\ the first pixel

LDA R                  \ Fetch the pixel byte from R, which we set in part 2 to
\ the horizontal pixel number within the character block
\ where the line starts (so it's 0, 1, 2 or 3)

BEQ LI200              \ If R = 0, jump to LI200 to start plotting from the
\ first pixel in this byte

CMP #2                 \ If R < 2 (i.e. R = 1), jump to LI210 to start plotting
BCC LI210              \ from the second pixel in this byte

CLC                    \ Clear the C flag so it doesn't affect the additions
\ below

BEQ LI220              \ If R = 2, jump to LI220 to start plotting from the
\ third pixel in this byte

BNE LI230              \ If we get here then R must be 3, so jump to LI130 to
\ start plotting from the fourth pixel in this byte
\ (this BNE is effectively a JMP as by now R is never
\ zero)

.LI200

LDA #%10001000         \ Set a mask in A to the first pixel in the 4-pixel byte
\ (note that this value is modified by the code at the
\ start of this section to be a bit mask for the colour
\ in COL)

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

DEX                    \ Decrement the counter in X

BEQ LIEX               \ If we have just reached the right end of the line,

LDA S                  \ Set S = S + Q to update the slope error
STA S

CLC                    \ Otherwise we just overflowed, so clear the C flag and
INY                    \ increment Y to move to the pixel line below

BEQ LI201              \ If Y is zero we need to move down into the character
\ address accordingly (jumping back to LI210 afterwards)

.LI210

LDA #%01000100         \ Set a mask in A to the second pixel in the 4-pixel
\ byte (note that this value is modified by the code at
\ the start of this section to be a bit mask for the
\ colour in COL)

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

DEX                    \ Decrement the counter in X

BEQ LIEX               \ If we have just reached the right end of the line,

LDA S                  \ Set S = S + Q to update the slope error
STA S

CLC                    \ Otherwise we just overflowed, so clear the C flag and
INY                    \ increment Y to move to the pixel line below

BEQ LI211              \ If Y is zero we need to move down into the character
\ address accordingly (jumping back to LI220 afterwards)

.LI220

LDA #%00100010         \ Set a mask in A to the third pixel in the 4-pixel byte
\ (note that this value is modified by the code at the
\ start of this section to be a bit mask for the colour
\ in COL)

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

DEX                    \ Decrement the counter in X

BEQ LIEX2              \ If we have just reached the right end of the line,

LDA S                  \ Set S = S + Q to update the slope error
STA S

CLC                    \ Otherwise we just overflowed, so clear the C flag and
INY                    \ increment Y to move to the pixel line below

BEQ LI221              \ If Y is zero we need to move down into the character
\ address accordingly (jumping back to LI230 afterwards)

.LI230

LDA #%00010001         \ Set a mask in A to the fourth pixel in the 4-pixel
\ byte (note that this value is modified by the code at
\ the start of this section to be a bit mask for the
\ colour in COL)

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

LDA S                  \ Set S = S + Q to update the slope error
STA S

CLC                    \ Otherwise we just overflowed, so clear the C flag and
INY                    \ increment Y to move to the pixel line below

BEQ LI231              \ If Y is zero we need to move down into the character
\ address accordingly (jumping back to LI240 afterwards)

.LI240

DEX                    \ Decrement the counter in X

BEQ LIEX2              \ If we have just reached the right end of the line,

LDA SC                 \ Add 8 to SC, so SC(1 0) now points to the next
ADC #8                 \ character along to the right
STA SC

BCC LI200              \ If the addition didn't overflow, jump back to LI200
\ to plot the next pixel

INC SC+1               \ Otherwise the low byte of SC(1 0) just overflowed, so
\ increment the high byte SC+1 as we just crossed over
\ into the right half of the screen

CLC                    \ Clear the C flag to avoid breaking any arithmetic

BCC LI200              \ Jump back to LI200 to plot the next pixel

.LI201

INC SC+1               \ If we get here then we need to move down into the
INC SC+1               \ character block below, so we increment the high byte
LDY #248               \ of the screen twice (as there are two pages per screen
\ row) and set the pixel line to the first line in that
\ character block (as we subtracted 248 from SC above)

BNE LI210              \ Jump back to the instruction after the BMI that called
\ this routine

.LI211

INC SC+1               \ If we get here then we need to move down into the
INC SC+1               \ character block below, so we increment the high byte
LDY #248               \ of the screen twice (as there are two pages per screen
\ row) and set the pixel line to the first line in that
\ character block (as we subtracted 248 from SC above)

BNE LI220              \ Jump back to the instruction after the BMI that called
\ this routine

.LI221

INC SC+1               \ If we get here then we need to move down into the
INC SC+1               \ character block below, so we increment the high byte
LDY #248               \ of the screen twice (as there are two pages per screen
\ row) and set the pixel line to the first line in that
\ character block (as we subtracted 248 from SC above)

BNE LI230              \ Jump back to the instruction after the BMI that called
\ this routine

.LI231

INC SC+1               \ If we get here then we need to move down into the
INC SC+1               \ character block below, so we increment the high byte
LDY #248               \ of the screen twice (as there are two pages per screen
\ row) and set the pixel line to the first line in that
\ character block (as we subtracted 248 from SC above)

BNE LI240              \ Jump back to the instruction after the BMI that called
\ this routine

.LIEX2

RTS                    \ Return from the subroutine
```