Skip to navigation

Elite on the BBC Micro and NES

Drawing lines: LOIN (Part 3 of 7)

[Acorn Electron version]

Name: LOIN (Part 3 of 7) [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a shallow line going right and up or left and down 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: * The line is going right and up (no swap) or left and down (swap) * X1 < X2 and Y1-1 > Y2 * Draw from (X1, Y1) at bottom left to (X2, Y2) at top right, omitting the first pixel
LDA SWAP \ If SWAP > 0 then we swapped the coordinates above, so BNE LI6 \ jump down to LI6 to skip plotting the first pixel \ \ This appears to be a bug that omits the last pixel \ of this type of shallow line, rather than the first \ pixel, which makes the treatment of this kind of line \ different to the other kinds of slope (they all have a \ BEQ instruction at this point, rather than a BNE) \ \ The result is a rather messy line join when a shallow \ line that goes right and up or left and down joins a \ line with any of the other three types of slope \ \ This bug was fixed in the advanced versions of Elite, \ where the BNE is replaced by a BEQ to bring it in line \ with the other three slopes DEX \ Decrement the counter in X because we're about to plot \ the first pixel .LIL2 \ We now loop 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 R \ Fetch the pixel byte from R EOR (SC),Y \ Store R into screen memory at SC(1 0), using EOR STA (SC),Y \ logic so it merges with whatever is already on-screen .LI6 LSR R \ Shift the single pixel in R to the right to step along \ the x-axis, so the next pixel we plot will be at the \ next x-coordinate along BCC LI7 \ If the pixel didn't fall out of the right end of R \ into the C flag, then jump to LI7 ROR R \ Otherwise we need to move over to the next character \ block, so first rotate R right so the set C flag goes \ back into the left end, giving %10000000 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 LI7 \ If the addition of the low bytes of SC overflowed, INC SC+1 \ increment the high byte .LI7 LDA S \ Set S = S + Q to update the slope error ADC Q STA S BCC LIC2 \ If the addition didn't overflow, jump to LIC2 DEY \ Otherwise we just overflowed, so decrement Y to move \ to the pixel line above BPL LIC2 \ If Y is positive we are still within the same \ character block, so skip to LIC2 \ We now need to move up into the character block above, \ and each character row in screen memory takes up &140 \ bytes (&100 for the visible part and &20 for each of \ the blank borders on the side of the screen), so \ that's what we need to subtract from SC(1 0) LDA SC \ Set SC(1 0) = SC(1 0) - &140 SBC #&40 \ STA SC \ Starting with the low bytes LDA SC+1 \ And then subtracting the high bytes SBC #&01 STA SC+1 LDY #7 \ Set the pixel line to the last line in that character \ block .LIC2 DEX \ Decrement the counter in X BNE LIL2 \ If we haven't yet reached the right end of the line, \ loop back to LIL2 to plot the next pixel along LDY YSAV \ Restore Y from YSAV, so that it's preserved RTS \ Return from the subroutine