This code appears in the following versions (click to see it in the source code):
Code variations between these versions are shown below.
.STPY LDY Y1 \ Set A = Y = Y1 TYA LDX X1 \ Set X = X1 CPY Y2 \ If Y1 >= Y2, jump down to LI15, as the coordinates are BCS LI15 \ 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 STA Y1 STY Y2 TAY \ Set Y = A = Y1 .LI15 \ By this point we know the line is vertical-ish and \ Y1 >= Y2, so we're going from top to bottom as we go \ from Y1 to Y2Type: Subroutine Category: Drawing lines Summary: Draw a line: Line has a steep gradient, step up along y-axis 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: * |delta_y| >= |delta_x| * The line is closer to being vertical than horizontal * We are going to step up along the y-axis * We potentially swap coordinates to make sure Y1 >= Y2
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
This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.
BCC P%+4 \ If bit 7 of X1 was set, so X1 > 127, increment the INC SC+1 \ high byte of SC(1 0) to point to the second page on \ this screen row, as this page contains the right half \ of the row
This variation is blank in the Electron version.
Tap on a block to expand it, and tap it again to revert.
LDA TWOS,X \ Fetch a 1-pixel byte from TWOS where pixel X is set, STA R \ and store it in R
Part 5 of the LOIN routine in the advanced versions uses logarithms to speed up the multiplication.
This variation is blank in the 6502 Second Processor and Master versions.
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)
This variation is blank in the Cassette, Disc (flight), Disc (docked), 6502 Second Processor and Master versions.
TXA \ Set X = X1 mod 8, which is the pixel column within the AND #7 \ character block at which we want to draw the start of TAX \ our line (as each character block has 8 rows) LDA TWOS,X \ Fetch a mode 4 1-pixel byte with the pixel position STA R \ at X and store it in R to act as a mask
Part 5 of the LOIN routine in the advanced versions uses logarithms to speed up the multiplication.
Tap on a block to expand it, and tap it again to revert.
The Master version omits half of the logarithm algorithm when compared to the 6502SP version.
See below for more variations related to this code.
This variation is blank in the Cassette, Disc (flight), Disc (docked), Master and Electron versions.
BMI LIloG \ If A > 127, jump to LIloG
Code variation 11 of 13
See variation 10 above for details.
This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.
Tap on a block to expand it, and tap it again to revert.
Code variation 12 of 13
See variation 10 above for details.
This variation is blank in the Cassette, Disc (flight), Disc (docked), Master and Electron versions.
LDA #255 \ The division is very close to 1, so set A to the BNE LIlog2 \ closest possible answer to 256, i.e. 255, and jump to \ LIlog2 to return the result (this BNE is effectively a \ JMP as A is never zero) .LIloG LDX P \ Subtract the high bytes of log(P) - log(Q) so now A LDA log,X \ contains the high byte of log(P) - log(Q) LDX Q SBC log,X BCS LIlog3 \ If the subtraction fitted into one byte and didn't \ underflow, then log(P) - log(Q) < 256, so we jump to \ LIlog3 to return a result of 255 TAX \ Otherwise we set A to the A-th entry from the LDA antilogODD,X \ antilogODD so the result of the division is now in A
Code variation 13 of 13
See variation 10 above for details.
This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.
.LIlog2 STA P \ Store the result of the division in P, so we have: \ \ P = |delta_x| / |delta_y| .LIfudge LDX Q \ Set X = Q \ = |delta_y| BEQ LIEX7 \ If |delta_y| = 0, jump down to LIEX7 to return from \ the subroutine INX \ Set X = Q + 1 \ = |delta_y| + 1 \ \ We add 1 so we can skip the first pixel plot if the \ line is being drawn with swapped coordinates LDA X2 \ Set A = X2 - X1 SEC SBC X1 BCS P%+6 \ If X2 >= X1 then skip the following two instructions JMP LFT \ If X2 < X1 then jump to LFT, as we need to draw the \ line to the left and down .LIEX7 RTS \ Return from the subroutine