Skip to navigation

Maths (Geometry): GetRotationMatrix (Part 1 of 5)

Name: GetRotationMatrix (Part 1 of 5) [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Calculate the rotation matrix for rotating the pitch or yaw angle for the sights into the global 3D coordinate system
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * GetVectorForAngles calls GetRotationMatrix

This routine is used to calculate the following: sinAngle = sin(vectorPitchAngle) cosAngle = cos(vectorPitchAngle) or: sinAngle = sin(vectorYawAngle) cosAngle = cos(vectorYawAngle) We can use these to convert the pitch and yaw angles of the vector from the player's eyes to the sights into a cartesian vector within the 3D world. This routine is from Revs, Geoff Crammond's previous game. There are only minor differences: the argument is (A T) instead of (A X), and the value of X is preserved. Note that to avoid clashing names, the variables G and H have been renamed to G2 and H2, but the routine is otherwise the same. For the calculations in The Sentinel we don't need a full rotation matrix, but the Revs routine calculates the values that we do need, as mentioned above. I could have renamed this routine for The Sentinel to something like GetSinAndCos16, as all it does is calculate the sine and cosine to 16-bit accuracy, but I've left the Revs code alone as much as possible to show the influence of Geoff Crammond's previous game. Also, because this routine comes from Revs, where it is only used to rotate through the driver's yaw angle, I have renamed the result variables from sinYawAngle and cosYawAngle to sinAngle and cosAngle, as The Sentinel uses the routine to rotate through both yaw angles and pitch angles. To keep things simple the commentary still refers to yaw angles, but the calculations apply equally to pitch angles.
Arguments: (A T) The pitch or yaw angle to encapsulate in the rotation matrix
Returns: X X is preserved
.GetRotationMatrix STA J \ Set (J T) = (A T) \ = vectorYawAngle or vectorPitchAngle \ \ Note that because this routine is copied almost \ verbatim from Revs, the commentary only refers to yaw \ angles, but this routine can work just as well with \ pitch angles as arguments STX xStoreMatrix \ Store X in xStoreMatrix so it can be preserved across \ calls to the routine JSR GetAngleInRadians \ Set (U A) to the vectorYawAngle, reduced to a quarter \ circle, converted to radians, and halved \ \ Let's call this yawRadians / 2, where yawRadians is \ the reduced player yaw angle in radians STA G2 \ Set (U G) = (U A) = yawRadians / 2 LDA U \ Set (A G) = (U G) = yawRadians / 2 STA H2 \ Set (H G) = (A G) = yawRadians / 2 \ So we now have: \ \ (H G) = (A G) = (U G) = yawRadians / 2 \ \ This is the angle vector that we now project onto the \ x- and z-axes of the world 3D coordinate system LDX #1 \ Set X = 0 and secondAxis = 1, so we project sin(H G) STX secondAxis \ into sinAngle and cos(H G) into cosAngle LDX #0 BIT J \ If bit 6 of J is clear, then vectorYawAngle is in one BVC rotm1 \ of these ranges: \ \ * 0 to 63 (%00000000 to %00111111) \ \ * -128 to -65 (%10000000 to %10111111) \ \ The degree system in the Sentinel looks like this: \ \ 0 \ -32 | +32 Overhead view of player \ \ | / \ \ | / 0 = looking straight ahead \ \|/ +64 = looking sharp right \ -64 -----+----- +64 -64 = looking sharp left \ /|\ \ / | \ \ / | \ \ -96 | +96 \ 128 \ \ So vectorYawAngle is in the top-right or bottom-left \ quarter in the above diagram \ \ In both cases we jump to rotm1 to set sinAngle and \ cosAngle \ If we get here then bit 6 of J is set, so \ vectorYawAngle is in one of these ranges: \ \ * 64 to 127 (%01000000 to %01111111) \ \ * -64 to -1 (%11000000 to %11111111) \ \ So vectorYawAngle is in the bottom-right or top-left \ quarter in the above diagram \ \ In both cases we set the variables the other way \ round, as the triangle we draw to calculate the angle \ is the opposite way round (i.e. it's reflected in the \ x-axis or y-axis) INX \ Set X = 1 and secondAxis = 0, so we project sin(H G) DEC secondAxis \ into cosAngle and cos(H G) into sinAngle \ We now enter a loop that sets sinAngle + X to \ sin(H G) on the first iteration, and sets \ sinAngle + secondAxis to cos(H G) on the second \ iteration \ \ The commentary is for the sin(H G) iteration, see the \ end of the loop for details of how the second \ iteration calculates cos(H G) instead .rotm1 \ If we get here, then we are set up to calculate the \ following: \ \ * If vectorYawAngle is top-right or bottom-left: \ \ sinAngle = sin(vectorYawAngle) \ cosAngle = cos(vectorYawAngle) \ \ * If vectorYawAngle is bottom-right or top-left: \ \ sinAngle = cos(vectorYawAngle) \ cosAngle = sin(vectorYawAngle) \ \ In each case, the calculation gives us the correct \ coordinate, as the second set of results uses angles \ that are "reflected" in the x-axis or y-axis by the \ capping process in the GetAngleInRadians routine CMP #122 \ If A < 122, i.e. U < 122 and H < 122, jump to rotm2 BCC rotm2 \ to calculate sin(H G) for smaller angles BCS rotm3 \ Jump to rotm3 to calculate sin(H G) for larger angles \ (this BCS is effectively a JMP as we just passed \ through a BCS) LDA G2 \ It doesn't look like this code is ever reached, so CMP #240 \ presumably it's left over from development BCS rotm3