.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 Y2 LSR A ; Set T1 = A >> 3 LSR A ; = y div 8 LSR A ; STA T1 ; So T1 now contains the number of the character row ; that will contain the pixel we want to draw TAY ; Set the low byte of SC(1 0) to the Y-th entry from LDA SCTBL,Y ; SCTBL, which contains the low byte of the address of STA SC ; the start of character row Y in screen memory LDA Y1 ; Set T2 = Y1 mod 8, which is the pixel row within the AND #7 ; character block at which we want to draw our pixel (as STA T2 ; each character block has 8 rows) ASL A ; Set the high byte of SC(1 0) as follows: ASL A ; ADC SCTBH,Y ; SC+1 = SCBTH for row Y + pixel row * 4 STA SC+1 ; ; Because this is the high byte, and because we already ; set the low byte in SC to the Y-th entry from SCTBL, ; this is the same as the following: ; ; SC(1 0) = (SCBTH SCTBL) for row Y + pixel row * $400 ; ; So SC(1 0) contains the address in screen memory of ; the pixel row containing the pixel we want to draw, as ; (SCBTH SCTBL) gives us the address of the start of the ; character row, and each pixel row within the character ; row is offset by $400 bytes LDY SCTBX1,X ; Using the lookup table at SCTBX1, set Y to the bit ; number within the pixel byte that corresponds to the ; pixel at the x-coordinate in X, i.e. the start of the ; line (so Y is in the range 0 to 6, as bit 7 in the ; pixel byte is used to set the pixel byte's colour ; palette) LDA TWOS,Y ; Fetch a one-pixel byte from TWOS where pixel Y is set, STA R ; and store it in R LDY SCTBX2,X ; Using the lookup table at SCTBX2, set Y to the byte ; number within the pixel row that contains the start of ; the line ; The following section calculates: ; ; P = P / Q ; = |delta_x| / |delta_y| ; ; using the log tables at logL and log to calculate: ; ; A = log(P) - log(Q) ; = log(|delta_x|) - log(|delta_y|) ; ; by first subtracting the low bytes of the logarithms ; from the table at LogL, and then subtracting the high ; bytes from the table at log, before applying the ; antilog to get the result of the division and putting ; it in P LDX P ; Set X = |delta_x| BEQ LIfudge ; If |delta_x| = 0, jump to LIfudge to return 0 as the ; result of the division LDA logL,X ; Set A = log(P) - log(Q) LDX Q ; = log(|delta_x|) - log(|delta_y|) SEC ; SBC logL,X ; by first subtracting the low bytes of log(P) - log(Q) LDX P ; And then subtracting the high bytes of log(P) - log(Q) LDA log,X ; so now A contains the high byte of log(P) - log(Q) LDX Q SBC log,X BCC P%+6 ; If the subtraction underflowed then skip the next two ; instructions as log(P) - log(Q) >= 256 ; Otherwise the subtraction fitted into one byte and ; didn't underflow, so log(P) - log(Q) < 256, and we ; now return a result of 255 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) TAX ; Otherwise we set A to the A-th entry from the LDA alogh,X ; alogh so the result of the division is now in A .LIlog2 STA P ; Store the result of the division in P, so we have: ; ; P = |delta_x| / |delta_y| .LIfudge SEC ; Set the C flag for the subtraction below LDX Q ; Set X = Q + 1 INX ; = |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 SBC X1 BCC LFT ; If X2 < X1 then jump to LFT, as we need to draw the ; line to the left and downName: LOIN (Part 5 of 7) [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a line: Line has a steep gradient, step up along y-axis Deep dive: Bresenham's line algorithmContext: See this subroutine in context in the source code 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 vertical than horizontal * We are going to step up along the y-axis * We potentially swap coordinates to make sure Y1 >= Y2
[X]
Label LFT in subroutine LOIN (Part 7 of 7)
[X]
Label LI15 is local to this routine
[X]
Label LIfudge is local to this routine
[X]
Label LIlog2 is local to this routine
[X]
Variable SCTBH (category: Drawing the screen)
Lookup table for converting a character row number to the address of the top pixel line in that character row (high byte)
[X]
Variable SCTBL (category: Drawing the screen)
Lookup table for converting a character row number to the address of the top or bottom pixel line in that character row (low byte)
[X]
Variable SCTBX1 (category: Drawing the screen)
Lookup table for converting a pixel x-coordinate to the bit number within the pixel row byte that corresponds to this pixel
[X]
Variable SCTBX2 (category: Drawing the screen)
Lookup table for converting a pixel x-coordinate to the byte number in the pixel row that corresponds to this pixel
[X]
Variable TWOS (category: Drawing pixels)
Ready-made bytes for drawing one-pixel dots in the space view
[X]
Variable alogh (category: Maths (Arithmetic))
Binary antilogarithm table
[X]
Variable log (category: Maths (Arithmetic))
Binary logarithm table (high byte)
[X]
Variable logL (category: Maths (Arithmetic))
Binary logarithm table (low byte)