Skip to navigation


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 on the BBC Micro
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 * LOINQ (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.
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 four-pixel horizontal line of EOR (SC),Y \ colour COL in SC(1 0) so that it draws the line STA (SC),Y \ on-screen, 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