Skip to navigation

Aviator on the BBC Micro

Dashboard: GetHandVector

Name: GetHandVector [Show more] Type: Subroutine Category: Dashboard Summary: Vector line calculation for a hand on indicators 0 to 6 Deep dive: Clock hands and dial indicators
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * DrawIndicatorHand calls GetHandVector

Arguments: A The value to show as a hand on the dial indicator Returns: W Magnitude of x-coordinate of line's vector |x-delta| G Magnitude of y-coordinate of line's vector |y-delta| R Direction of vector (T, U): * Bit 7 is the direction of the x-delta * Bit 6 is the direction of the y-delta Direction is like a clock, so positive (clear) is up and right, so this means the following: * x-delta +ve, y-delta +ve: 12 to 3 o'clock * x-delta +ve, y-delta -ve: 3 to 6 o'clock * x-delta -ve, y-delta -ve: 6 to 9 o'clock * x-delta -ve, y-delta +ve: 9 to 12 o'clock
.GetHandVector LDY #0 \ Set R = 0, to use as the first guess for the direction STY R \ of the hand on the dial (we will change it below if \ required) LDY dialQuadrant,X \ Set Y = the dialQuadrant value for this indicator, \ which is the size of a quarter of the dial in terms of \ the value in A INY \ Set K = Y + 1 STY K \ = dialQuadrant + 1 \ \ Doing this enables us to subtract this value below, \ leaving the result in a suitable state for negating \ using two's complement (see dhvc2) SEC \ Set the C flag for the subtraction we are about to do .dhvc1 SBC K \ Set A = A - K \ = A - (dialQuadrant + 1) \ \ so we have subtracted a quadrant's worth of value from \ the value we want to show in A BCS dhvc2 \ If the subtraction didn't underflow, jump to dhvc2 to \ skip the following two instructions \ The subtraction underflowed, so we know that the hand \ is in the first quadrant, i.e 3 to 6 o'clock ADC K \ Reverse the subtraction by adding K to A, so A is now \ back to its original value JMP dhvc6 \ Jump down to dhvc5 to calculate the hand's vector, \ with R set to 0 to indicate that both the x-delta and \ y-delta for the line are positive .dhvc2 SBC dialQuadrant,X \ Subtract a second quadrant's worth, so: \ \ A = A - (dialQuadrant + 1) - dialQuadrant \ = A - 2 * dialQuadrant - 1 \ \ If we want to negate this value below, then we can do \ this using two's complement by simply inverting all \ the bits, as we have already subtracted 1, and we can \ negate by either inverting-and-adding-1, or by \ subtracting-1-and-inverting (as they are equivelent) BCS dhvc3 \ If the subtraction didn't underflow, jump to dhvc3 to \ skip the following three instructions \ The subtraction underflowed, so we know that the hand \ is in the second quadrant, i.e 6 to 9 o'clock LDY #%01000000 \ Set bit 6 of R to indicate that the x-delta for the STY R \ line is positive and the y-delta is negative BNE dhvc5 \ Jump down to dhvc5 to negate A before calculating the \ hand's vector (this BNE is effectively a JMP as A is \ never zero) .dhvc3 SBC K \ Subtract a third quadrant's worth BCS dhvc4 \ If the subtraction didn't underflow, jump to dhvc4 to \ skip the following four instructions \ The subtraction underflowed, so we know that the hand \ is in the third quadrant on the dial ADC K \ Reverse the subtraction by adding K to A, so A is now \ back to its original value LDY #%11000000 \ Set bits 7 and 6 of R to indicate that both the STY R \ x-delta and y-delta for the line are negative BNE dhvc6 \ Jump down to dhvc5 to calculate the hand's vector \ (this BNE is effectively a JMP as A is never zero) .dhvc4 SBC dialQuadrant,X \ Subtract a fourth quadrant's worth BCS dhvc1 \ If the subtraction didn't underflow, jump to dhvc1 to \ start the subtraction process again, as we have now \ subtracted a whole dial's worth and need to keep going \ The subtraction underflowed, so we know that the hand \ is in the fourth quadrant on the dial LDY #%10000000 \ Set bit 7 of R to indicate that the x-delta for the STY R \ line is negative and the y-delta is positive .dhvc5 \ If we get here then the hand is either in the second \ or fourth quadrant on the dial EOR #&FF \ Invert the value of A (i.e. negate it) using two's \ complement, which works because we can negate a number \ by subtracting 1 and then inverting, and we \ effectively subtracted 1 in the above by using K .dhvc6 \ By the time we get here, the direction of the new \ dial hand is in R, the value of A has been reduced \ into negative territory by repeated subtraction, and \ it has been switched to be positive if the quadrant is \ bottom-right or top-left, i.e. 3 to 6 o'clock or \ 9 to 12 o'clock) \ \ We now use this value of A as our value of x in the \ above calculation STA S \ Store the reduced value of A in S \ We now calculate y-delta, where y = w - x or y = x - w \ depending on the quadrant. We already set the sign of \ x correctly with the above EOR, so if we calculate \ y = w - x, it will be correct LDA dialQuadrant,X \ Set A = the dialQuadrant value for this indicator, \ which is the size of a quarter of the dial in terms of \ the value in A. This is what we use for w in the above SEC \ Set A = A - S SBC S \ = w - x \ \ so A contains our y-delta \ We now cap the y-delta, which has the effect of \ blunting the points of our diamond CMP yDeltaMax,X \ If A < yDeltaMax for this indicator, jump to dhvc7 to BCC dhvc7 \ skip the following instruction LDA yDeltaMax,X \ Set A = yDeltaMax, so A is never greater than the \ yDeltaMax value for this indicator .dhvc7 CLC \ Set G = A + 1 ADC #1 \ = y-delta + 1 STA G \ \ so G contains the y-delta, plus 1 to ensure it is \ non-zero LDA S \ Fetch the reduced value of A that we stored in S we \ above, which we know is our x-delta CLC \ Set A = (A + 1) / 2 ADC #1 \ LSR A \ because mode 5 pixels are twice as wide as they are \ high, so this scales the x-delta to be a pixel value CMP xDeltaMax,X \ If A < xDeltaMax for this indicator, jump to dhvc8 to BCC dhvc8 \ skip the following instruction LDA xDeltaMax,X \ Set A = xDeltaMax, so A is never greater than the \ xDeltaMax value for this indicator .dhvc8 CLC \ Set W = A + 1 ADC #1 \ = x-delta + 1 STA W \ \ so W contains the y-delta, plus 1 to ensure it is \ non-zero RTS \ Return from the subroutine