Skip to navigation

Drawing lines: LOIN (Part 3 of 7)

[Apple II 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 Drawing pixels in the Apple II version
Context: 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: * The line is going right and up (no swap) or left and down (swap) * X1 < X2 and Y1 > 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 ASL R ; Shift the single pixel in R to the left to step along ; the x-axis, so the next pixel we plot will be at the ; next x-coordinate along (we shift left because the ; pixels in the high-resolution screen are the opposite ; way around than the bits in the pixel byte) BPL LI7 ; If the pixel didn't fall out of the left end of the ; pixel bits in R into the palette bit in bit 7, then ; jump to LI7 LDA #%00000001 ; Otherwise we need to move over to the next character STA R ; block, so set R = %00000001 to move the pixel to the ; left end of the next pixel byte INY ; And increment Y to move on to the next character block ; along to the right .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 DEC T2 ; Otherwise we just overflowed, so decrement the pixel ; row counter within the character block, which is in ; T2, as we are moving to a new pixel line BMI LI20 ; If T2 is negative then the counter just ran down and ; we are no longer within the same character block, so ; jump to LI20 to move to the bottom pixel row in the ; character row above ; We now need to move up into the pixel row above LDA SC+1 ; Subtract 4 from the high byte of SC(1 0), so this does SBC #4 ; the following: STA SC+1 ; ; SC(1 0) = SC(1 0) - $400 ; ; The SBC works because the C flag is set, as we passed ; through the BCC above ; ; So this sets SC(1 0) to the address of the pixel row ; above the one we just drew in, as each pixel row ; within the character row is spaced out by $400 bytes ; in screen memory .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 .LI20 ; If we get here then we need to move up into the bottom ; pixel row in the character block above LDA #7 ; Set the pixel line number within the character row STA T2 ; (which we store in T2) to 7, which is the bottom pixel ; row of the character block above STX T ; Store the current character row number in T, so we can ; restore it below LDX T1 ; Decrement the number of the character row in T1, as we DEX ; are moving up a row STX T1 LDA SCTBL,X ; Set SC(1 0) to the X-th entry from (SCTBH2 SCTBL), so STA SC ; it contains the address of the start of the bottom LDA SCTBH2,X ; pixel row in character row X in screen memory (so ; that's the bottom pixel row in the character row we ; just moved up into) ; ; We set the high byte below (though there's no reason ; why it isn't done here) LDX T ; Restore the value of X that we stored, so X contains ; the previous character row number, from before we ; moved up a row (we need to do this as the following ; jump returns us to a point where the previous row ; number is still in X) STA SC+1 ; Set the high byte of SC(1 0) as above JMP LIC2 ; Jump back to keep drawing the line