Elite on the BBC Micro and NES

# Drawing lines: LOIN (Part 2 of 7)

## [BBC Micro disc version, Docked]

```       Name: LOIN (Part 2 of 7)                                      [Show more]
Type: Subroutine
Category: Drawing lines
Summary: Draw a line: Line has a shallow gradient, step right along x-axis
Deep dive: Bresenham's line algorithm
Context: See this subroutine in context in the source code
Variations: See code variations for this subroutine in the different versions
References: No direct references to this subroutine in this source file

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

* |delta_y| < |delta_x|

* The line is closer to being horizontal than vertical

* We are going to step right along the x-axis

* We potentially swap coordinates to make sure X1 < X2

.STPX

LDX X1                 \ Set X = X1

CPX X2                 \ If X1 < X2, jump down to LI3, as the coordinates are
BCC LI3                \ already in the order that we want

DEC SWAP               \ Otherwise decrement SWAP from 0 to &FF, to denote that
\ we are swapping the coordinates around

LDA X2                 \ Swap the values of X1 and X2
STA X1
STX X2

TAX                    \ Set X = X1

LDA Y2                 \ Swap the values of Y1 and Y2
LDY Y1
STA Y1
STY Y2

.LI3

\ By this point we know the line is horizontal-ish and
\ X1 < X2, so we're going from left to right as we go
\ from X1 to X2

LDA Y1                 \ Set A = Y1 / 8, so A now contains the character row
LSR A                  \ that will contain our horizontal line
LSR A
LSR A

ORA #&60               \ As A < 32, this effectively adds &60 to A, which gives
\ us the screen address of the character row (as each
\ character row takes up 256 bytes, and the first
\ character row is at screen address &6000, or page &60)

STA SCH                \ Store the page number of the character row in SCH, so
\ the high byte of SC is set correctly for drawing the
\ start of our line

LDA Y1                 \ Set Y = Y1 mod 8, which is the pixel row within the
AND #7                 \ character block at which we want to draw the start of
TAY                    \ our line (as each character block has 8 rows)

TXA                    \ Set A = bits 3-7 of X1
AND #%11111000

STA SC                 \ Store this value in SC, so SC(1 0) now contains the
\ screen address of the far left end (x-coordinate = 0)
\ of the horizontal pixel row that we want to draw the
\ start of our line on

TXA                    \ Set X = X1 mod 8, which is the horizontal pixel number
AND #7                 \ within the character block where the line starts (as
TAX                    \ each pixel line in the character block is 8 pixels
\ wide)

LDA TWOS,X             \ Fetch a 1-pixel byte from TWOS where pixel X is set,
STA R                  \ and store it in R

\ The following calculates:
\
\   Q = Q / P
\     = |delta_y| / |delta_x|
\
\ using the same shift-and-subtract algorithm that's
\ documented in TIS2

LDA Q                  \ Set A = |delta_y|

LDX #%11111110         \ Set Q to have bits 1-7 set, so we can rotate through 7
STX Q                  \ loop iterations, getting a 1 each time, and then
\ getting a 0 on the 8th iteration... and we can also
\ use Q to catch our result bits into bit 0 each time

.LIL1

ASL A                  \ Shift A to the left

BCS LI4                \ If bit 7 of A was set, then jump straight to the
\ subtraction

CMP P                  \ If A < P, skip the following subtraction
BCC LI5

.LI4

SBC P                  \ A >= P, so set A = A - P

SEC                    \ Set the C flag to rotate into the result in Q

.LI5

ROL Q                  \ Rotate the counter in Q to the left, and catch the
\ result bit into bit 0 (which will be a 0 if we didn't
\ do the subtraction, or 1 if we did)

BCS LIL1               \ If we still have set bits in Q, loop back to TIL2 to
\ do the next iteration of 7

\ We now have:
\
\   Q = A / P
\     = |delta_y| / |delta_x|
\
\ and the C flag is clear

LDX P                  \ Set X = P + 1
INX                    \       = |delta_x| + 1
\
\ We add 1 so we can skip the first pixel plot if the
\ line is being drawn with swapped coordinates

LDA Y2                 \ Set A = Y2 - Y1 - 1 (as the C flag is clear following
SBC Y1                 \ the above division)

BCS DOWN               \ If Y2 >= Y1 - 1 then jump to DOWN, as we need to draw
\ the line to the right and down
```