Skip to navigation

Elite on the BBC Micro

Dashboard: SCAN (Master version)

Name: SCAN [View in context] Type: Subroutine [Compare versions] Category: Dashboard Summary: Display the current ship on the scanner Deep dive: The 3D scanner
This is used both to display a ship on the scanner, and to erase it again. Arguments: INWK The ship's data block
.SC5 RTS \ Return from the subroutine .SCAN LDA INWK+31 \ Fetch the ship's scanner flag from byte #31 AND #%00010000 \ If bit 4 is clear then the ship should not be shown BEQ SC5 \ on the scanner, so return from the subroutine (as SC5 \ contains an RTS) LDX TYPE \ Fetch the ship's type from TYPE into X BMI SC5 \ If this is the planet or the sun, then the type will \ have bit 7 set and we don't want to display it on the \ scanner, so return from the subroutine (as SC5 \ contains an RTS) LDA scacol,X \ Set A to the scanner colour for this ship type from \ the X-th entry in the scacol table STA COL \ Store the scanner colour in COL so it can be used to \ draw this ship in the correct colour LDA INWK+1 \ If any of x_hi, y_hi and z_hi have a 1 in bit 6 or 7, ORA INWK+4 \ then the ship is too far away to be shown on the ORA INWK+7 \ scanner, so return from the subroutine (as SC5 AND #%11000000 \ contains an RTS) BNE SC5 \ If we get here, we know x_hi, y_hi and z_hi are all \ 63 (%00111111) or less \ Now, we convert the x_hi coordinate of the ship into \ the screen x-coordinate of the dot on the scanner, \ using the following (see the deep dive on "The 3D \ scanner" for an explanation): \ \ X1 = 123 + (x_sign x_hi) LDA INWK+1 \ Set x_hi CLC \ Clear the C flag so we can do addition below LDX INWK+2 \ Set X = x_sign BPL SC2 \ If x_sign is positive, skip the following EOR #%11111111 \ x_sign is negative, so flip the bits in A and subtract ADC #1 \ 1 to make it a negative number (bit 7 will now be set \ as we confirmed above that bits 6 and 7 are clear). So \ this gives A the sign of x_sign and gives it a value \ range of -63 (%11000001) to 0 CLC \ Clear the C flag so we can do addition below .SC2 ADC #125 \ Set X1 = 125 + x_hi AND #%11111110 \ STA X1 \ and if the result is odd, subtract 1 to make it even TAX \ Set X = X1 - 2 DEX DEX \ Next, we convert the z_hi coordinate of the ship into \ the y-coordinate of the base of the ship's stick, \ like this (see the deep dive on "The 3D scanner" for \ an explanation): \ \ SC = 220 - (z_sign z_hi) / 4 \ \ though the following code actually does it like this: \ \ SC = 255 - (35 + z_hi / 4) LDA INWK+7 \ Set A = z_hi / 4 LSR A \ LSR A \ So A is in the range 0-15 CLC \ Clear the C flag LDY INWK+8 \ Set Y = z_sign BPL SC3 \ If z_sign is positive, skip the following EOR #%11111111 \ z_sign is negative, so flip the bits in A and set the SEC \ C flag. As above, this makes A negative, this time \ with a range of -16 (%11110000) to -1 (%11111111). And \ as we are about to do an ADC, the SEC effectively adds \ another 1 to that value, giving a range of -15 to 0 .SC3 ADC #35 \ Set A = 35 + A to give a number in the range 20 to 50 EOR #%11111111 \ Flip all the bits and store in Y2, so Y2 is in the STA Y2 \ range 205 to 235, with a higher z_hi giving a lower Y2 \ Now for the stick height, which we calculate using the \ following (see the deep dive on "The 3D scanner" for \ an explanation): \ \ A = - (y_sign y_hi) / 2 LDA INWK+4 \ Set A = y_hi / 2 LSR A CLC \ Clear the C flag LDY INWK+5 \ Set Y = y_sign BMI SCD6 \ If y_sign is negative, skip the following, as we \ already have a positive value in A EOR #%11111111 \ y_sign is positive, so flip the bits in A and set the SEC \ C flag. This makes A negative, and as we are about to \ do an ADC below, the SEC effectively adds another 1 to \ that value to implement two's complement negation, so \ we don't need to add another 1 here .SCD6 \ We now have all the information we need to draw this \ ship on the scanner, namely: \ \ X1 = the screen x-coordinate of the ship's dot \ \ SC = the screen y-coordinate of the base of the \ stick \ \ A = the screen height of the ship's stick, with the \ correct sign for adding to the base of the stick \ to get the dot's y-coordinate \ \ First, though, we have to make sure the dot is inside \ the dashboard, by moving it if necessary ADC Y2 \ Set A = Y2 + A, so A now contains the y-coordinate of \ the end of the stick, plus the length of the stick, to \ give us the screen y-coordinate of the dot BPL FIXIT \ If the result has bit 0 clear, then the result has \ overflowed and is bigger than 256, so jump to FIXIT to \ set A to the maximum allowed value of 246 (this \ instruction isn't required as we test both the maximum \ and minimum below, but it might save a few cycles) CMP #194 \ If A >= 194, skip the following instruction, as 194 is BCS P%+4 \ the minimum allowed value of A LDA #194 \ A < 194, so set A to 194, the minimum allowed value \ for the y-coordinate of our ship's dot CMP #247 \ If A < 247, skip the following instruction, as 246 is BCC P%+4 \ the maximum allowed value of A .FIXIT LDA #246 \ A >= 247, so set A to 246, the maximum allowed value \ for the y-coordinate of our ship's dot 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 JSR CPIX2 \ Call CPIX2 to draw a single-height dash at the \ y-coordinate in A, and return the dash's right pixel \ byte in R, which we use below LDA Y1 \ Fetch the y-coordinate back into A, which was stored \ in Y1 by the call to CPIX2 SEC \ Set A = A - Y2 to get the stick length, by reversing SBC Y2 \ the ADC Y2 we did above. This clears the C flag if the \ result is negative (i.e. the stick length is negative) \ and sets it if the result is positive (i.e. the stick \ length is negative) \ So now we have the following: \ \ X1 = the screen x-coordinate of the ship's dot, \ clipped to fit into the dashboard \ \ Y1 = the screen y-coordinate of the ship's dot, \ clipped to fit into the dashboard \ \ SC = the screen y-coordinate of the base of the \ stick \ \ A = the screen height of the ship's stick, with the \ correct sign for adding to the base of the stick \ to get the dot's y-coordinate \ \ C = 0 if A is negative, 1 if A is positive \ \ and we can get on with drawing the dot and stick BEQ RTS \ If the stick height is zero, then there is no stick to \ draw, so return from the subroutine (as RTS contains \ an RTS) BCC VL3 \ If the C flag is clear then the stick height in A is \ negative, so jump down to RTS+1 TAX \ Copy the (positive) stick height into X INX \ Increment the (positive) stick height in X JMP VLL1a \ Jump into the middle of the VLL1 loop, skipping the \ drawing of first pixel in the stick .VLL1 LDA R \ The call to CPIX2 above saved the dash's right pixel \ byte in R, so we load this into A (so the stick comes \ out of the right side of the dot) EOR (SC),Y \ Draw the bottom row of the double-height dot using the STA (SC),Y \ same byte as the top row, plotted using EOR logic .VLL1a \ If we get here then the stick length is positive (so \ the dot is below the ellipse and the stick is above \ the dot, and we need to draw the stick upwards from \ the dot) DEY \ We want to draw the stick upwards, so decrement the \ pixel row in Y BPL VL1 \ If Y is still positive then it correctly points at the \ line above, so jump to VL1 to skip the following LDA SC+1 \ Subtract 2 from the high byte of the screen address to SBC #2 \ move to the character block above STA SC+1 LDY #7 \ We just decremented Y up through the top of the \ character block, so we need to move it to the last row \ in the character above, so set Y to 7, the number of \ the last row .VL1 DEX \ Decrement the (positive) stick height in X BNE VLL1 \ If we still have more stick to draw, jump up to VLL1 \ to draw the next pixel .RTS LDA #%00001001 \ Clear bits 1 and 2 of the Access Control Register at STA VIA+&34 \ SHEILA &34 to switch main memory back into &3000-&7FFF RTS .VL3 \ If we get here then the stick length is negative (so \ the dot is above the ellipse and the stick is below \ the dot, and we need to draw the stick downwards from \ the dot) LDA Y2 \ Set A = Y2 - Y1 to get the positive stick height SEC SBC Y1 TAX \ Copy the (positive) stick height into X INX \ Increment the (positive) stick height in X JMP VLL2a \ Jump into the middle of the VLL2 loop, skipping the \ drawing of first pixel in the stick .VLL2 LDA R \ The call to CPIX2 above saved the dash's right pixel \ byte in R, so we load this into A (so the stick comes \ out of the right side of the dot) EOR (SC),Y \ Draw the bottom row of the double-height dot using the STA (SC),Y \ same byte as the top row, plotted using EOR logic .VLL2a INY \ We want to draw the stick itself, heading downwards, \ so increment the pixel row in Y CPY #8 \ If the row number in Y is less than 8, then it BNE VL2 \ correctly points at the next line down, so jump to \ VL2 to skip the following LDA SC+1 \ We just incremented Y down through the bottom of the ADC #1 \ character block, so increment the high byte of the STA SC+1 \ screen address to move to the character block above LDY #0 \ We need to move to the first row in the character \ below, so set Y to 0, the number of the first row .VL2 DEX \ Decrement the (positive) stick height in X BNE VLL2 \ If we still have more stick to draw, jump up to VLL2 \ to draw the next pixel LDA #%00001001 \ Clear bits 1 and 2 of the Access Control Register at STA VIA+&34 \ SHEILA &34 to switch main memory back into &3000-&7FFF RTS \ Return from the subroutine