Elite on the BBC Micro and NES

# Drawing lines: LL145 (Part 1 of 4)

## [BBC Micro disc version, Flight]

```       Name: LL145 (Part 1 of 4)                                     [Show more]
Type: Subroutine
Category: Drawing lines
Summary: Clip line: Work out which end-points are on-screen, if any
Deep dive: Line-clipping
Extended screen coordinates
Context: See this subroutine in context in the source code
Variations: See code variations for this subroutine in the different versions
References: This subroutine is called as follows:
* BLINE calls LL145
* LL9 (Part 9 of 12) calls LL145
* LL9 (Part 10 of 12) calls via LL147

This routine clips the line from (x1, y1) to (x2, y2) so it fits on-screen, or
returns an error if it can't be clipped to fit. The arguments are 16-bit
coordinates, and the clipped line is returned using 8-bit screen coordinates.

This part sets XX13 to reflect which of the two points are on-screen and
off-screen.

Arguments:

XX15(1 0)            x1 as a 16-bit coordinate (x1_hi x1_lo)

XX15(3 2)            y1 as a 16-bit coordinate (y1_hi y1_lo)

XX15(5 4)            x2 as a 16-bit coordinate (x2_hi x2_lo)

XX12(1 0)            y2 as a 16-bit coordinate (y2_hi y2_lo)

Returns:

(X1, Y1)             Screen coordinate of the start of the clipped line

(X2, Y2)             Screen coordinate of the end of the clipped line

C flag               Clear if the clipped line fits on-screen, set if it
doesn't

XX13                 The state of the original coordinates on-screen:

* 0   = (x2, y2) on-screen

* 95  = (x1, y1) on-screen,  (x2, y2) off-screen

* 191 = (x1, y1) off-screen, (x2, y2) off-screen

So XX13 is non-zero if the end of the line was clipped,
meaning the next line sent to BLINE can't join onto the
end but has to start a new segment

SWAP                 The swap status of the returned coordinates:

* &FF if we swapped the values of (x1, y1) and
(x2, y2) as part of the clipping process

* 0 if the coordinates are still in the same order

Y                    Y is preserved

Other entry points:

LL147                Don't initialise the values in SWAP or A

.LL145

LDA #0                 \ Set SWAP = 0
STA SWAP

LDA XX15+5             \ Set A = x2_hi

.LL147

LDX #Y*2-1             \ Set X = #Y * 2 - 1. The constant #Y is 96, the
\ y-coordinate of the mid-point of the space view, so
\ this sets Y2 to 191, the y-coordinate of the bottom
\ pixel row of the space view

ORA XX12+1             \ If one or both of x2_hi and y2_hi are non-zero, jump
BNE LL107              \ to LL107 to skip the following, leaving X at 191

CPX XX12               \ If y2_lo > the y-coordinate of the bottom of screen
BCC LL107              \ then (x2, y2) is off the bottom of the screen, so skip
\ the following instruction, leaving X at 191

LDX #0                 \ Set X = 0

.LL107

STX XX13               \ Set XX13 = X, so we have:
\
\   * XX13 = 0 if x2_hi = y2_hi = 0, y2_lo is on-screen
\
\   * XX13 = 191 if x2_hi or y2_hi are non-zero or y2_lo
\            is off the bottom of the screen
\
\ In other words, XX13 is 191 if (x2, y2) is off-screen,
\ otherwise it is 0

LDA XX15+1             \ If one or both of x1_hi and y1_hi are non-zero, jump
ORA XX15+3             \ to LL83
BNE LL83

LDA #Y*2-1             \ If y1_lo > the y-coordinate of the bottom of screen
CMP XX15+2             \ then (x1, y1) is off the bottom of the screen, so jump
BCC LL83               \ to LL83

\ If we get here, (x1, y1) is on-screen

LDA XX13               \ If XX13 is non-zero, i.e. (x2, y2) is off-screen, jump
BNE LL108              \ to LL108 to halve it before continuing at LL83

\ If we get here, the high bytes are all zero, which
\ means the x-coordinates are < 256 and therefore fit on
\ screen, and neither coordinate is off the bottom of
\ the screen. That means both coordinates are already on
\ screen, so we don't need to do any clipping, all we
\ need to do is move the low bytes into (X1, Y1) and
\ X2, Y2) and return

.LL146

\ If we get here then we have clipped our line to the
\ (if we had to clip it at all), so we move the low
\ bytes from (x1, y1) and (x2, y2) into (X1, Y1) and
\ (X2, Y2), remembering that they share locations with
\ XX15:
\
\   X1 = XX15
\   Y1 = XX15+1
\   X2 = XX15+2
\   Y2 = XX15+3
\
\ X1 already contains x1_lo, so now we do the rest

LDA XX15+2             \ Set Y1 (aka XX15+1) = y1_lo
STA XX15+1

LDA XX15+4             \ Set X2 (aka XX15+2) = x2_lo
STA XX15+2

LDA XX12               \ Set Y2 (aka XX15+3) = y2_lo
STA XX15+3

CLC                    \ Clear the C flag as the clipped line fits on-screen

RTS                    \ Return from the subroutine

.LL109

SEC                    \ Set the C flag to indicate the clipped line does not
\ fit on-screen

RTS                    \ Return from the subroutine

.LL108

LSR XX13               \ If we get here then (x2, y2) is off-screen and XX13 is
\ 191, so shift XX13 right to halve it to 95
```