Skip to navigation

Elite on the BBC Micro and NES

Drawing lines: LOIN (Part 2 of 7)

[BBC Micro disc version, Docked]

Name: LOIN (Part 2 of 7) [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a line: Line has a shallow gradient, step right along x-axis 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: * |delta_y| < |delta_x| * The line is closer to being horizontal than vertical * We are going to step right along the x-axis * We potentially swap coordinates to make sure X1 < X2
.STPX LDX X1 \ Set X = X1 CPX X2 \ If X1 < X2, jump down to LI3, as the coordinates are BCC LI3 \ 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 LDY Y1 STA Y1 STY Y2 .LI3 \ By this point we know the line is horizontal-ish and \ X1 < X2, so we're going from left to right as we go \ from X1 to X2 LDA Y1 \ Set A = Y1 / 8, so A now contains the character row LSR A \ that will contain our horizontal line LSR A LSR A ORA #&60 \ As A < 32, this effectively adds &60 to A, which gives \ us the screen address of the character row (as each \ character row takes up 256 bytes, and the first \ character row is at screen address &6000, or page &60) STA SCH \ Store the page number of the character row in SCH, so \ the high byte of SC is set correctly for drawing the \ start of our line 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) TXA \ Set A = bits 3-7 of X1 AND #%11111000 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 TXA \ Set X = X1 mod 8, which is the horizontal pixel number AND #7 \ within the character block where the line starts (as TAX \ each pixel line in the character block is 8 pixels \ wide) LDA TWOS,X \ Fetch a 1-pixel byte from TWOS where pixel X is set, STA R \ and store it in R \ The following calculates: \ \ Q = Q / P \ = |delta_y| / |delta_x| \ \ using the same shift-and-subtract algorithm that's \ documented in TIS2 LDA Q \ Set A = |delta_y| LDX #%11111110 \ Set Q to have bits 1-7 set, so we can rotate through 7 STX Q \ loop iterations, getting a 1 each time, and then \ getting a 0 on the 8th iteration... and we can also \ use Q to catch our result bits into bit 0 each time .LIL1 ASL A \ Shift A to the left BCS LI4 \ If bit 7 of A was set, then jump straight to the \ subtraction CMP P \ If A < P, skip the following subtraction BCC LI5 .LI4 SBC P \ A >= P, so set A = A - P SEC \ Set the C flag to rotate into the result in Q .LI5 ROL Q \ Rotate the counter in Q to the left, and catch the \ result bit into bit 0 (which will be a 0 if we didn't \ do the subtraction, or 1 if we did) BCS LIL1 \ If we still have set bits in Q, loop back to TIL2 to \ do the next iteration of 7 \ We now have: \ \ Q = A / P \ = |delta_y| / |delta_x| \ \ and the C flag is clear LDX P \ Set X = P + 1 INX \ = |delta_x| + 1 \ \ We add 1 so we can skip the first pixel plot if the \ line is being drawn with swapped coordinates LDA Y2 \ Set A = Y2 - Y1 - 1 (as the C flag is clear following SBC Y1 \ the above division) BCS DOWN \ If Y2 >= Y1 - 1 then jump to DOWN, as we need to draw \ the line to the right and down