Skip to navigation

Elite on the BBC Micro

Version analysis of LOIN (Part 3 of 7)

This code appears in the following versions (click to see it in the source code):

Code variations between these versions are shown below.

Name: LOIN (Part 3 of 7) Type: Subroutine Category: Drawing lines Summary: Draw a shallow line going right and up or left and down Deep dive: Bresenham's line algorithm
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)

Code variation 1 of 9A variation in the comments only

Tap on a version to expand it, and tap it again to show to all variations.

Cassette, Flight, Docked, Electron

6502SP, Master

* X1 < X2 and Y1-1 > Y2
* X1 < X2 and Y1 > Y2
* Draw from (X1, Y1) at bottom left to (X2, Y2) at top right

Code variation 2 of 9A variation in the comments only

This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.

6502SP, Master

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.

Code variation 3 of 9Related to the screen mode

This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.

6502SP, Master

LDA #%10001000 \ Modify the value in the LDA instruction at LI100 below AND COL \ to contain a pixel mask for the first pixel in the STA LI100+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 LI110 below AND COL \ to contain a pixel mask for the second pixel in the STA LI110+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 LI120 below AND COL \ to contain a pixel mask for the third pixel in the STA LI120+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 LI130 below AND COL \ to contain a pixel mask for the fourth pixel in the STA LI130+1 \ 4-pixel byte, in the colour COL, so that it draws in \ the correct colour

Code variation 4 of 9Related to the screen mode

This variation is blank in the 6502 Second Processor and Master versions.

Cassette, Flight, Docked, Electron

LDA SWAP \ If SWAP > 0 then we swapped the coordinates above, so BNE LI6 \ jump down to LI6 to skip plotting the first pixel 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

Code variation 5 of 9Related to the screen mode

This variation is blank in the Cassette, Disc (flight), Disc (docked), 6502 Second Processor and Master versions.

Electron

BCC LI7 \ If the addition of the low bytes of SC overflowed, INC SC+1 \ increment the high byte

Code variation 6 of 9Related to the screen mode

This variation is blank in the 6502 Second Processor and Master versions.

Cassette, Flight, Docked, Electron

.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

Code variation 7 of 9Related to the screen mode

This variation is blank in the 6502 Second Processor and Master versions.

Tap on a version to expand it, and tap it again to show to all variations.

Cassette, Flight, Docked

Electron

DEC SCH \ Otherwise we need to move up into the character block LDY #7 \ above, so decrement the high byte of the screen \ address and set the pixel line to the last line in \ that character block
\ 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

Code variation 8 of 9Related to the screen mode

This variation is blank in the 6502 Second Processor and Master versions.

Cassette, Flight, Docked, Electron

.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

Code variation 9 of 9Related to the screen mode

This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.

6502SP, Master

\ 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 LI190 \ so jump down to LI190 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 LI100+6 \ If R = 0, jump to LI100+6 to start plotting from the \ second pixel in this byte (LI100+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 LI110+6 to skip the BCC LI110+6 \ first two pixels but plot the next two CLC \ Clear the C flag so it doesn't affect the additions \ below BEQ LI120+6 \ If R = 2, jump to LI120+6 to to skip the first three \ pixels but plot the last one BNE LI130+6 \ If we get here then R must be 3, so jump to LI130+6 to \ skip plotting any of the pixels, but making sure we \ join the routine just after the plotting instructions .LI190 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 LI100 \ If R = 0, jump to LI100 to start plotting from the \ first pixel in this byte CMP #2 \ If R < 2 (i.e. R = 1), jump to LI110 to start plotting BCC LI110 \ from the second pixel in this byte CLC \ Clear the C flag so it doesn't affect the additions \ below BEQ LI120 \ If R = 2, jump to LI120 to start plotting from the \ third pixel in this byte JMP LI130 \ If we get here then R must be 3, so jump to LI130 to \ start plotting from the fourth pixel in this byte .LI100 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 .LIEXS BEQ LIEX \ If we have just reached the right end of the line, \ jump to LIEX to return from the subroutine LDA S \ Set S = S + Q to update the slope error ADC Q STA S BCC LI110 \ If the addition didn't overflow, jump to LI110 CLC \ Otherwise we just overflowed, so clear the C flag and DEY \ decrement Y to move to the pixel line above BMI LI101 \ If Y is negative we need to move up into the character \ block above, so jump to LI101 to decrement the screen \ address accordingly (jumping back to LI110 afterwards) .LI110 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, \ jump to LIEX to return from the subroutine LDA S \ Set S = S + Q to update the slope error ADC Q STA S BCC LI120 \ If the addition didn't overflow, jump to LI120 CLC \ Otherwise we just overflowed, so clear the C flag and DEY \ decrement Y to move to the pixel line above BMI LI111 \ If Y is negative we need to move up into the character \ block above, so jump to LI111 to decrement the screen \ address accordingly (jumping back to LI120 afterwards) .LI120 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 LIEX \ If we have just reached the right end of the line, \ jump to LIEX to return from the subroutine LDA S \ Set S = S + Q to update the slope error ADC Q STA S BCC LI130 \ If the addition didn't overflow, jump to LI130 CLC \ Otherwise we just overflowed, so clear the C flag and DEY \ decrement Y to move to the pixel line above BMI LI121 \ If Y is negative we need to move up into the character \ block above, so jump to LI121 to decrement the screen \ address accordingly (jumping back to LI130 afterwards) .LI130 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 ADC Q STA S BCC LI140 \ If the addition didn't overflow, jump to LI140 CLC \ Otherwise we just overflowed, so clear the C flag and DEY \ decrement Y to move to the pixel line above BMI LI131 \ If Y is negative we need to move up into the character \ block above, so jump to LI131 to decrement the screen \ address accordingly (jumping back to LI140 afterwards) .LI140 DEX \ Decrement the counter in X BEQ LIEX \ If we have just reached the right end of the line, \ jump to LIEX to return from the subroutine 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 LI100 \ If the addition didn't overflow, jump back to LI100 \ 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 LI100 \ Jump back to LI100 to plot the next pixel .LI101 DEC SC+1 \ If we get here then we need to move up into the DEC SC+1 \ character block above, so we decrement the high byte LDY #7 \ of the screen twice (as there are two pages per screen \ row) and set the pixel line to the last line in \ that character block BPL LI110 \ Jump back to the instruction after the BMI that called \ this routine .LI111 DEC SC+1 \ If we get here then we need to move up into the DEC SC+1 \ character block above, so we decrement the high byte LDY #7 \ of the screen twice (as there are two pages per screen \ row) and set the pixel line to the last line in \ that character block BPL LI120 \ Jump back to the instruction after the BMI that called \ this routine .LI121 DEC SC+1 \ If we get here then we need to move up into the DEC SC+1 \ character block above, so we decrement the high byte LDY #7 \ of the screen twice (as there are two pages per screen \ row) and set the pixel line to the last line in \ that character block BPL LI130 \ Jump back to the instruction after the BMI that called \ this routine .LI131 DEC SC+1 \ If we get here then we need to move up into the DEC SC+1 \ character block above, so we decrement the high byte LDY #7 \ of the screen twice (as there are two pages per screen \ row) and set the pixel line to the last line in \ that character block BPL LI140 \ Jump back to the instruction after the BMI that called \ this routine .LIEX
 RTS                    \ Return from the subroutine

RSS Feed