Skip to navigation

Elite on the BBC Micro and NES

Drawing lines: HLOIN

[BBC Master version]

Name: HLOIN [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a horizontal line from (X1, Y1) to (X2, Y1) Deep dive: Drawing colour pixels in mode 5
Context: See this subroutine in context in the source code Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * HLOIN2 calls HLOIN * SUN (Part 3 of 4) calls HLOIN * LOIN (Part 1 of 7) calls via HLOIN3 * NLIN2 calls via HLOIN3 * TT15 calls via HLOIN3

This routine draws a horizontal orange line in the space view. We do not draw a pixel at the right end of the line. To understand how this routine works, you might find it helpful to read the deep dive on "Drawing colour pixels in mode 5".
Returns: Y Y is preserved
Other entry points: HLOIN3 Draw a line from (X, Y1) to (X2, Y1) in the colour given in A
.HLOIN LDA Y1 \ Set A = Y1, the pixel y-coordinate of the line AND #3 \ Set A to the correct order of red/yellow pixels to TAX \ make this line an orange colour (by using bits 0-1 of LDA orange,X \ the pixel y-coordinate as the index into the orange \ lookup table) STA COL \ Store the correct orange colour in COL .HLOIN3 STY YSAV \ Store Y into YSAV, so we can preserve it across the \ call to this subroutine LDY #%00001111 \ Set bits 1 and 2 of the Access Control Register at STY VIA+&34 \ SHEILA &34 to switch screen memory into &3000-&7FFF 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 LDY Y1 \ Look up the page number of the character row that LDA ylookup,Y \ contains the pixel with the y-coordinate in Y1, and STA SC+1 \ store it in SC+1, so the high byte of SC is set \ correctly for drawing our line TYA \ Set A = Y1 mod 8, which is the pixel row within the AND #7 \ character block at which we want to draw our line (as \ each character block has 8 rows) 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 our \ horizontal line on TXA \ Set Y = 2 * bits 2-6 of X1 AND #%11111100 \ ASL A \ and shift bit 7 of X1 into the C flag TAY 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 .HL1 TXA \ Set T = bits 2-7 of X1, which will contain the AND #%11111100 \ character number of the start of the line * 4 STA T LDA X2 \ Set A = bits 2-7 of X2, which will contain the AND #%11111100 \ character number of the end of the line * 4 SEC \ Set A = A - T, which will contain the number of SBC T \ character blocks we need to fill - 1 * 4 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 R = A / 4, so R now contains the number of LSR A \ character blocks we need to fill - 1 STA R LDA X1 \ Set X = X1 mod 4, which is the horizontal pixel number AND #3 \ within the character block where the line starts (as TAX \ each pixel line in the character block is 4 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 AND COL \ Apply the pixel mask in A to the four-pixel block of \ coloured pixels in COL, so we now know which bits to \ set in screen memory to paint the relevant pixels in \ the required colour 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 BCS HL7 \ If the above addition overflowed, then we have just \ crossed over from the left half of the screen into the \ right half, so call HL7 to increment the high byte in \ SC+1 so that SC(1 0) points to the page in screen \ memory for the right half of the screen row. HL7 also \ clears the C flag and jumps back to HL8, so this acts \ like a conditional JSR instruction .HL8 LDX R \ Fetch the number of character blocks we need to fill \ from R 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 COL \ Store a full-width 4-pixel horizontal line of colour EOR (SC),Y \ COL in SC(1 0) so that it draws the line on-screen, STA (SC),Y \ using EOR logic 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 BCS HL9 \ If the above addition overflowed, then we have just \ crossed over from the left half of the screen into the \ right half, so call HL9 to increment the high byte in \ SC+1 so that SC(1 0) points to the page in screen \ memory for the right half of the screen row. HL9 also \ clears the C flag and jumps back to HL10, so this acts \ like a conditional JSR instruction .HL10 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 #3 \ of the line, so set X = X2 mod 3, 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 AND COL \ Apply the pixel mask in A to the four-pixel block of \ coloured pixels in COL, so we now know which bits to \ set in screen memory to paint the relevant pixels in \ the required colour 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 .HL6 LDY #%00001001 \ Clear bits 1 and 2 of the Access Control Register at STY VIA+&34 \ SHEILA &34 to switch main memory back into &3000-&7FFF LDY YSAV \ Restore Y from YSAV, so that it's preserved 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 4, which is the horizontal pixel number AND #3 \ within the character block where the line starts (as TAX \ each pixel line in the character block is 4 pixels \ wide) LDA TWFR,X \ Fetch a ready-made byte with X pixels filled in at the STA T \ 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 4, which is the horizontal pixel number AND #3 \ 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 T \ We now have two bytes, one (T) 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 \ \ T = %00111111 \ A = %11111100 \ T AND A = %00111100 \ \ So we can stick T AND A in screen memory to get the \ line we want, which is what we do here by setting \ A = A AND T AND COL \ Apply the pixel mask in A to the four-pixel block of \ coloured pixels in COL, so we now know which bits to \ set in screen memory to paint the relevant pixels in \ the required colour 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 #%00001001 \ Clear bits 1 and 2 of the Access Control Register at STY VIA+&34 \ SHEILA &34 to switch main memory back into &3000-&7FFF LDY YSAV \ Restore Y from YSAV, so that it's preserved RTS \ Return from the subroutine .HL7 INC SC+1 \ We have just crossed over from the left half of the \ screen into the right half, so increment the high byte \ in SC+1 so that SC(1 0) points to the page in screen \ memory for the right half of the screen row CLC \ Clear the C flag (as HL7 is called with the C flag \ set, which this instruction reverts) JMP HL8 \ Jump back to HL8, just after the instruction that \ called HL7 .HL9 INC SC+1 \ We have just crossed over from the left half of the \ screen into the right half, so increment the high byte \ in SC+1 so that SC(1 0) points to the page in screen \ memory for the right half of the screen row CLC \ Clear the C flag (as HL9 is called with the C flag \ set, which this instruction reverts) JMP HL10 \ Jump back to HL10, just after the instruction that \ called HL9