.GetAngleFromCoords \ We start by calculating the following using a similar \ shift-and-subtract algorithm as Revs: \ \ T = 256 * (A T) / (V W) \ \ In Revs, W is always zero, so there is some extra code \ below to cater for a full 16-bit value in (V W) ASL T \ Shift T left, which clears bit 0 of T, ready for us to \ start building the result in T at the same time as we \ shift the low byte of (A T) out to the left \ We now repeat the following seven-instruction block \ eight times, one for each bit in T ROL A \ Shift the high byte of (A T) to the left to extract \ the next bit from the number being divided BCS gang1 \ If we just shifted a 1 out of A, skip the next few \ instructions and jump straight to the subtraction CMP V \ If A < V then jump to gang2 with the C flag clear, so BCC gang2 \ we shift a 0 into the result in T \ This part of the routine has been added to the Revs \ algorithm to cater for both arguments being full \ 16-bit values (in Revs the second value always has a \ low byte of zero) BNE gang1 \ If A > V then jump to gang1 to calculate a full 16-bit \ subtraction \ If we get here then A = V LDY T \ If T < W then jump to gang2 with the C flag clear, so CPY W \ we shift a 0 into the result in T BCC gang2 .gang1 \ If we get here then T >= W and A >= V, so we know that \ (A T) >= (V W) \ \ We now calculate (A T) - (V W) as the subtraction part \ of the shift-and-subtract algorithm STA U \ Store A in U so we can retrieve it after the following \ calculation LDA T \ Subtract the low bytes as T = T - W SBC W \ STA T \ This calculation works as we know the C flag is set, \ as we passed through a BCC above LDA U \ Restore the value of A from before the subtraction SBC V \ Subtract the high bytes as A = A - V SEC \ Set the C flag so we shift a 1 into the result in T .gang2 ROL T \ Shift the result in T to the left, pulling the C flag \ into bit 0 ROL A \ Repeat the 16-bit shift-and-subtract loop for the BCS gang3 \ second shift CMP V BCC gang4 BNE gang3 LDY T CPY W BCC gang4 .gang3 STA U \ Repeat the 16-bit subtraction for the second shift LDA T SBC W STA T LDA U SBC V SEC .gang4 ROL T \ Shift the result for the second shift into T ROL A \ Repeat the 16-bit shift-and-subtract loop for the BCS gang5 \ third shift CMP V BCC gang6 BNE gang5 LDY T CPY W BCC gang6 .gang5 STA U \ Repeat the 16-bit subtraction for the third shift LDA T SBC W STA T LDA U SBC V SEC .gang6 PHP \ Store the C flag on the stack, so the stack contains \ the result bit from shifting and subtracting the third \ shift CMP V \ If A = V then jump to gang10 with the C flag set, as BEQ gang10 \ we can skip the rest of the shifts and still get a \ good result ASL T \ Shift a zero for the third shift into T, so bit 5 of \ the result is always clear \ \ We do this so we can set this bit later, depending on \ the value that we stored on the stack above ROL A \ Repeat the shift-and-subtract loop for the fourth BCS P%+6 \ shift CMP V BCC P%+5 SBC V SEC ROL T ROL A \ Repeat the shift-and-subtract loop for the fifth shift BCS P%+6 CMP V BCC P%+5 SBC V SEC ROL T ROL A \ Repeat the shift-and-subtract loop for the sixth shift BCS P%+6 CMP V BCC P%+5 SBC V SEC ROL T ROL A \ Repeat the shift-and-subtract loop for the seventh BCS P%+6 \ shift CMP V BCC P%+5 SBC V SEC ROL T ROL A \ Repeat the shift-and-subtract loop for the eighth BCS P%+6 \ shift CMP V BCC P%+5 SBC V SEC ROL T \ We now have the division result that we want: \ \ T = 256 * (A T) / (V W) \ \ but with bit 5 clear rather than the actual result \ \ This result can be used to look up the resulting angle \ from the arctangent table, but first we continue the \ division to enable us to improve accuracyName: GetAngleFromCoords (Part 1 of 3) [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Given the coordinates along two axes, calculate the pitch or yaw angle to those coordinatesContext: See this subroutine in context in the source code References: This subroutine is called as follows: * GetHypotenuseAngle calls GetAngleFromCoords
The first part of this routine is based on the Divide16x16 routine in Revs, Geoff Crammond's previous game, except it supports a divisor (V W) instead of (V 0), though only the top three bits of W are included in the calculation. The calculation is as follows: angle(Hi Lo) = arctan( (A T) / (V W) ) where (A T) < (V W).
Arguments: (A T) First coordinate as an unsigned integer (V W) Second coordinate as an unsigned integer
Returns: angle(Hi Lo) The pitch or yaw angle from the origin to the coordinate angleTangent Contains 256 * (A T) / (V W), which is the tangent of the pitch or yaw angle
[X]
Label gang1 is local to this routine
[X]
Label gang10 in subroutine GetAngleFromCoords (Part 2 of 3)
[X]
Label gang2 is local to this routine
[X]
Label gang3 is local to this routine
[X]
Label gang4 is local to this routine
[X]
Label gang5 is local to this routine
[X]
Label gang6 is local to this routine