Skip to navigation

Aviator on the BBC Micro

Drawing lines: DrawCanopyLine (Part 8 of 9)

Name: DrawCanopyLine (Part 8 of 9) [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a line as a steep vertical slope
Context: See this subroutine in context in the source code References: No direct references to this subroutine in this source file
.dlin45 \ By the time we get here, the code has been modified to \ work with the step directions given in bits 6 and 7 of \ V \ \ To keep things simple, we will only document the \ the default code, which is for a steep vertical slope \ with the following: \ \ * Bit 7 of V is clear, so we step along the x-axis \ in a positive direction, i.e. to the right \ \ * Bit 6 of V is clear, so we step along the y-axis \ in a positive direction, i.e. up the screen \ \ By this point, we also have the following variables \ set: \ \ * (Q P) is the screen address of the pixel row \ containing pixel (R, S), out by 8 bytes for each \ row above or below the top of the dashboard \ \ * I = W + 1, the x-coordinate for the end of the \ line + 1 \ \ * J = 7, the y-coordinate of the end of the line \ \ The last two have different values with different line \ directions, but these are the values for the default \ case that we're considering here LDA #159 \ Set Y = 159 - S SEC \ SBC S \ This gets added to the screen address in (Q P) that we TAY \ set above, to give the screen address of the starting \ point at coordinate (R, S) LDA #255 \ Set RR = 255 - U SEC \ = 255 - |y-delta| SBC U STA RR CLC \ Set SS = RR + 1 ADC #1 \ = 255 - U + 1 STA SS \ \ This is the starting value for the slope error LDA V \ If bits 0 and 1 of V are both clear, jump to dlin46 AND #%00000011 BEQ dlin46 LDA T \ If T < 2, jump to dlin46 CMP #2 BCC dlin46 LDA #255 \ Set SS = 255 for the starting slope error STA SS .dlin46 LDA R \ Set X = bits 0 and 1 of R, so X is the pixel number AND #%00000011 \ in the character row for pixel (R, S) TAX .dlin47 LDA #%00001000 \ Set A to a pixel byte with pixel 0 set to colour 1 \ \ Gets modified by the ModifyDrawRoutine routine: \ \ * LDA #8 when colourLogic = %10000000 \ \ * LDA #&80 when colourLogic = %01000000 \ \ In other words, this instruction has already been \ modified to implement the current colour logic CPX #0 \ If X = 0, then the pixel number for point (R, S) is 0, BEQ dlin49 \ so skip the following loop as the pixel is already in \ the right place \ Otherwise we right-shift A by X places to move the \ pixel to the right place .dlin48 LSR A \ Shift A to the right by one place DEX \ Decrement the shift counter BNE dlin48 \ Loop back until we have shifted A right by X places, \ so the pixel is now in the right place for point \ (R, S) within this pixel row .dlin49 STA H \ Store the pixel byte in H, which contains a single \ pixel in the correct colour in position X CLC \ Clear the C flag for the addition below LDX R \ Set X = R, so it contains the x-coordinate of the \ start of the line .dlin50 LDA H \ Set A to the pixel byte for point (R, S) within this \ pixel row \ \ Gets modified by the ModifyDrawRoutine routine: \ \ * LDA H when colourLogic = %01000000 \ or %10000000 \ \ * LDA #%00001111 when colourLogic = %00000000 \ and colourCycle = %00001111 \ \ * LDA #%11110000 when colourLogic = %00000000 \ and colourCycle = %11110000 \ \ In other words, this instruction has already been \ modified to implement the current colour cycle .dlin51 ORA (P),Y \ OR the pixel byte with the current screen contents \ \ Gets modified by the ModifyDrawRoutine routine: \ \ * ORA (P),Y when colourLogic = %01000000 \ \ * AND (P),Y when colourLogic = %00000000 \ \ In other words, this instruction has already been \ modified to implement the current drawing logic STA (P),Y \ Update the Y-th byte of (Q P) with the result, which \ sets 4 pixels to the pixel pattern in A, so this sets \ the pixel at screen coordinate (R, S) to the current \ colour LDA SS \ Set A = SS + T ADC T \ = slope error + |x-delta| \ \ so this updates the slope error as we move up one \ the screen one pixel at a time .dlin52 BCS dlin57 \ If the above addition overflowed, then the slope error \ just overflowed, so jump to dlin57 to move along the \ x-axis \ \ Gets modified by the DrawCanopyLine routine: \ \ * BCC dlin57 when bit 7 of V is clear \ \ * BCC dlin61 when bit 7 of V is set \ \ In other words, this instruction has already been \ modified to implement the current drawing direction STA SS \ Set SS = A to store the updated slope error in SS .dlin53 TYA \ Store the current y-coordinate in A \ \ Gets modified by the DrawCanopyLine routine: \ \ * TYA when bit 6 of V is clear \ \ * INY when bit 6 of V is set \ \ In other words, this instruction has already been \ modified to implement the current drawing direction .dlin54 DEY \ Decrement Y to move up a pixel row \ \ Gets modified by the DrawCanopyLine routine: \ \ * DEY when bit 6 of V is clear \ \ * TYA when bit 6 of V is set \ \ In other words, this instruction has already been \ modified to implement the current drawing direction AND #7 \ If A mod 7 <> 0 then we haven't reached the top of the BNE dlin50 \ 8-row character block, so loop back to dlin50 to draw \ the next row \ Otherwise we have reached the top row of the character \ block, so we now subtract &138 from (Q P) to move to \ the address of the bottom of the character block in \ the row above (as each character row in mode 5 \ contains &140 bytes, so this is &140 - 8 to cater for \ the block we just finished) \ \ Subtracting &138 is the same as adding &FEC8, so \ that's what we do now LDA P \ We start by adding &C8 to the low byte in P CLC .dlin55 ADC #&C8 \ Add &C8 to the low byte \ \ Gets modified by the DrawCanopyLine routine: \ \ * ADC #&C8 when bit 6 of V is clear \ \ * ADC #&38 when bit 6 of V is set \ \ In other words, this instruction has already been \ modified to implement the current drawing direction STA P \ Store the updated low byte in P LDA Q \ Then add the high bytes .dlin56 ADC #&FE \ Add &FE to the high byte \ \ Gets modified by the DrawCanopyLine routine: \ \ * ADC #&FE when bit 6 of V is clear \ \ * ADC #1 when bit 6 of V is set \ \ In other words, this instruction has already been \ modified to implement the current drawing direction STA Q \ Which we store in Q, so now we have: \ \ (Q P) = (Q P) + &FEC8 \ = (Q P) - &138 \ \ so (Q P) is the address of the end of the character \ block in the row above CPY J \ If the current y-coordinate in Y <> J, then we have CLC \ not yet reached the y-coordinate of the end of the BNE dlin50 \ line (which we set in part 7), so loop back to dlin50 \ to keep drawing the line JMP dlin65 \ Otherwise we have reached the y-coordinate of the end \ of the line, so jump to dlin65 to process the clipped \ part of the line, if applicable .dlin57 \ If we get here then the slope error just overflowed, \ and we are drawing up the screen (bit 7 of V is clear) \ \ We reached with a BCS, so we know the C flag is set \ \ We now need to move the line along the x-axis to the \ right by 1 pixel, which we do by shifting the single \ pixel in H to the right, and if it falls off the right \ end, adjusting the screen address in (Q P) to point to \ the next character block along ADC RR \ Set SS = A + RR + C STA SS \ = slope error + 255 - |y-delta| + 1 \ = slope error + 256 - |y-delta| \ = slope error - |y-delta| INX \ Increment X to move along the x-axis to the right LDA H \ Set A to the single pixel byte in H and shift it right LSR A \ to move the pixel along by one place .dlin58 CMP #%00000000 \ If the pixel byte is non-zero, then the pixel hasn't BNE dlin60 \ fallen off the end, so jump to dlin60 to skip the \ following \ \ Gets modified by the ModifyDrawRoutine routine: \ \ * CMP #%00000000 when colourLogic = %10000000 \ \ * CMP #%00001000 when colourLogic = %01000000 \ \ In other words, this instruction has already been \ modified to implement the current drawing logic LDA P \ Set (Q P) = (Q P) + 8 CLC \ ADC #8 \ starting with the low bytes STA P .dlin59 LDA #%00001000 \ Set A to a pixel byte with the leftmost pixel set, so \ we can use this as our new single pixel byte in H \ below (so shifting across by one character block only \ moves the single pixel right by one pixel) \ \ Gets modified by the ModifyDrawRoutine routine: \ \ * LDA #8 when colourLogic = %10000000 \ \ * LDA #&80 when colourLogic = %01000000 \ \ In other words, this instruction has already been \ modified to implement the current drawing logic BCC dlin60 \ And now add the high bytes, so (Q P) now points to the INC Q \ next character block to the right .dlin60 STA H \ Store the updated one-pixel byte in H CPX I \ If the current x-coordinate in X <> I, then we have CLC \ not yet reached the x-coordinate of the end of the BNE dlin53 \ line (which we set in part 7), so loop back to dlin53 \ to keep drawing the line BEQ dlin65 \ Otherwise we have reached the x-coordinate of the end \ of the line, so jump to dlin65 to process the clipped \ part of the line, if applicable (this BEQ is \ effectively a JMP as we just passed through a BNE) .dlin61 \ If we get here then the slope error just overflowed, \ and we are drawing down the screen (bit 7 of V is set) \ \ We reached with a BCS, so we know the C flag is set \ \ We now need to move the line along the x-axis to the \ left by 1 pixel, which we do by shifting the single \ pixel in H to the left, and if it falls off the left \ end, adjusting the screen address in (Q P) to point to \ the previous character block ADC RR \ Set SS = A + RR + C STA SS \ = slope error + 255 - |y-delta| + 1 \ = slope error + 256 - |y-delta| \ = slope error - |y-delta| DEX \ Decrement X to move along the x-axis to the left LDA H \ Set A to the single pixel byte in H and shift it left ASL A \ to move the pixel along by one place .dlin62 CMP #%00010000 \ If the pixel byte is not %00010000, then the pixel BNE dlin64 \ hasn't fallen off the end, so jump to dlin64 to skip \ the following \ \ Gets modified by the ModifyDrawRoutine routine: \ \ * CMP #%00010000 when colourLogic = %10000000 \ \ * CMP #%00000000 when colourLogic = %01000000 \ \ In other words, this instruction has already been \ modified to implement the current drawing logic LDA P \ Set (Q P) = (Q P) - 8 SEC \ SBC #8 \ starting with the low bytes STA P .dlin63 LDA #%00000001 \ Set A to a pixel byte with the rightmost pixel set, so \ we can use this as our new single pixel byte in H \ below (so shifting across by one character block only \ moves the single pixel left by one pixel) \ \ Gets modified by the ModifyDrawRoutine routine: \ \ * LDA #1 when colourLogic = %10000000 \ \ * LDA #16 when colourLogic = %01000000 \ \ In other words, this instruction has already been \ modified to implement the current drawing logic BCS dlin64 \ And now subtract the high bytes, so (Q P) now points DEC Q \ to the previous character block to the left .dlin64 STA H \ Store the updated one-pixel byte in H CPX I \ If the current x-coordinate in X <> I, then we have CLC \ not yet reached the x-coordinate of the end of the BNE dlin53 \ line (which we set in part 7), so loop back to dlin53 \ to keep drawing the line \ Otherwise we have reached the x-coordinate of the end \ of the line, so fall through into dlin65 to process \ the clipped part of the line, if applicable