Skip to navigation


Drawing lines: HLOIN

[Commodore 64 version]

Name: HLOIN [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a horizontal line from (X1, Y1) to (X2, Y1)
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * BOXS calls HLOIN * HLOIN2 calls HLOIN * SUN (Part 3 of 4) calls HLOIN
.HLOIN STY YSAV ; Store Y into YSAV, so we can preserve it across the ; call to this subroutine LDX X1 ; Set X = X1 CPX X2 ; If X1 = X2 then the start and end points are the same, BEQ HL6 ; so return from the subroutine (as HL6 contains an RTS) BCC HL5 ; If X1 < X2, jump to HL5 to skip the following code, as ; (X1, Y1) is already the left point LDA X2 ; Swap the values of X1 and X2, so we know that (X1, Y1) STA X1 ; is on the left and (X2, Y1) is on the right STX X2 TAX ; Set X = X1 .HL5 DEC X2 ; Decrement X2 so we do not draw a pixel at the end ; point LDA Y1 ; Set the low byte of SC(1 0) to Y1 mod 8, which is the TAY ; pixel row within the character block at which we want AND #7 ; to draw our line (as each character block has 8 rows) STA SC LDA ylookuph,Y ; Set the top byte of SC(1 0) to the address of the STA SC+1 ; start of the character row to draw in, from the ; ylookup table TXA ; Set A = bits 3-7 of X1 AND #%11111000 CLC ; The ylookup table lets us look up the 16-bit address ADC ylookupl,Y ; of the start of a character row containing a specific TAY ; pixel, so this fetches the address for the start of ; the character row containing the y-coordinate in Y, ; and adds it to the row offset we just calculated in A, ; storing the result in Y BCC P%+4 ; If the addition overflowed, increment the high byte INC SC+1 ; of SC(1 0), so SC(1 0) + Y gives us the correct ; address of the start of the line .HL1 TXA ; Set T2 = bits 3-7 of X1, which will contain the AND #%11111000 ; character number of the start of the line * 8 STA T2 LDA X2 ; Set A = bits 3-7 of X2, which will contain the AND #%11111000 ; character number of the end of the line * 8 SEC ; Set A = A - T2, which will contain the number of SBC T2 ; character blocks we need to fill - 1 * 8 BEQ HL2 ; If A = 0 then the start and end character blocks are ; the same, so the whole line fits within one block, so ; jump down to HL2 to draw the line ; Otherwise the line spans multiple characters, so we ; start with the left character, then do any characters ; in the middle, and finish with the right character LSR A ; Set R2 = A / 8, so R2 now contains the number of LSR A ; character blocks we need to fill - 1 LSR A STA R2 LDA X1 ; 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 TWFR,X ; Fetch a ready-made byte with X pixels filled in at the ; right end of the byte (so the filled pixels start at ; point X and go all the way to the end of the byte), ; which is the shape we want for the left end of the ; line EOR (SC),Y ; Store this into screen memory at SC(1 0), using EOR STA (SC),Y ; logic so it merges with whatever is already on-screen, ; so we have now drawn the line's left cap TYA ; Set Y = Y + 8 so (SC),Y points to the next character ADC #8 ; block along, on the same pixel row as before TAY BCC P%+4 ; If the addition overflowed, increment the high byte INC SC+1 ; of SC(1 0), so SC(1 0) + Y gives us the correct ; address of the pixel LDX R2 ; Fetch the number of character blocks we need to fill ; from R2 DEX ; Decrement the number of character blocks in X BEQ HL3 ; If X = 0 then we only have the last block to do (i.e. ; the right cap), so jump down to HL3 to draw it CLC ; Otherwise clear the C flag so we can do some additions ; while we draw the character blocks with full-width ; lines in them .HLL1 LDA #%11111111 ; Store a full-width 8-pixel horizontal line in SC(1 0) EOR (SC),Y ; so that it draws the line on-screen, using EOR logic STA (SC),Y ; so it merges with whatever is already on-screen TYA ; Set Y = Y + 8 so (SC),Y points to the next character ADC #8 ; block along, on the same pixel row as before TAY BCC P%+5 ; If the addition overflowed, increment the high byte INC SC+1 ; of SC(1 0), so SC(1 0) + Y gives us the correct CLC ; address of the start of the line ; ; We also clear the C flag so additions will work ; properly if we loop back for more DEX ; Decrement the number of character blocks in X BNE HLL1 ; Loop back to draw more full-width lines, if we have ; any more to draw .HL3 LDA X2 ; Now to draw the last character block at the right end AND #7 ; of the line, so set X = X2 mod 8, which is the TAX ; horizontal pixel number where the line ends LDA TWFL,X ; Fetch a ready-made byte with X pixels filled in at the ; left end of the byte (so the filled pixels start at ; the left edge and go up to point X), which is the ; shape we want for the right end of the line EOR (SC),Y ; Store this into screen memory at SC(1 0), using EOR STA (SC),Y ; logic so it merges with whatever is already on-screen, ; so we have now drawn the line's right cap LDY YSAV ; Restore Y from YSAV, so that it's preserved across the ; call to this subroutine RTS ; Return from the subroutine .HL2 ; If we get here then the entire horizontal line fits ; into one character block LDA X1 ; 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 TWFR,X ; Fetch a ready-made byte with X pixels filled in at the STA T2 ; right end of the byte (so the filled pixels start at ; point X and go all the way to the end of the byte) LDA X2 ; Set X = X2 mod 8, which is the horizontal pixel number AND #7 ; where the line ends TAX LDA TWFL,X ; Fetch a ready-made byte with X pixels filled in at the ; left end of the byte (so the filled pixels start at ; the left edge and go up to point X) AND T2 ; We now have two bytes, one (T2) containing pixels from ; the starting point X1 onwards, and the other (A) ; containing pixels up to the end point at X2, so we can ; get the actual line we want to draw by AND'ing them ; together. For example, if we want to draw a line from ; point 2 to point 5 (within the row of 8 pixels ; numbered from 0 to 7), we would have this: ; ; T2 = %00111111 ; A = %11111100 ; T2 AND A = %00111100 ; ; So we can stick T2 AND A in screen memory to get the ; line we want, which is what we do here by setting ; A = A AND T2 EOR (SC),Y ; Store our horizontal line byte into screen memory at STA (SC),Y ; SC(1 0), using EOR logic so it merges with whatever is ; already on-screen LDY YSAV ; Restore Y from YSAV, so that it's preserved RTS ; Return from the subroutine EQUD $F0E0C080 ; These bytes appear to be unused; they contain a copy EQUW $FCF8 ; of the TWFL variable, and the original source has a EQUB $FE ; commented out label .TWFL EQUD $1F3F7FFF ; These bytes appear to be unused; they contain a copy EQUD $0103070F ; of the TWFR variable, and the original source has a ; commented out label .TWFR