Skip to navigation

Revs on the BBC Micro

Track geometry: GetSegmentAngles (Part 2 of 3)

Name: GetSegmentAngles (Part 2 of 3) [Show more] Type: Subroutine Category: Track geometry Summary: Process a segment that is not visible by trying to process a segment that's one-quarter of the size Deep dive: Data structures for the track calculations The track verges
Context: See this subroutine in context in the source code References: No direct references to this subroutine in this source file
.gseg4 \ If we get here then the segment is not visible or the \ segment's pitch angle is negative, so we need to \ stop processing segments \ \ However, before we stop, we try to eke out as much \ accuracy out of the last (not visible) segment by \ trying to process a segment that's one-quarter of the \ size, just in case this smaller segment is visible, in \ which case we finish with something to show for the \ last visible segment (and if not, at least we tried) LDA segmentCounter \ If segmentCounter is non-zero then we have already BNE gseg5 \ found at least one visible segment, so jump to gseg5 RTS \ Otherwise this is the first segment and it's not \ visible, so return from the subroutine as none of the \ others will be either (as we are working backwards \ through the segments towards the player, so if the \ first segment is not visible, so will all the ones \ behind it) .gseg5 LDA #0 \ Set U = 0, to use as an axis counter below STA U LDY prevSegmentOffset \ Set Y to the offset from xSegmentCoordILo of the \ previous segment's 3D coordinates STX W \ Store the segment offset that's in X in W, so we can \ retrieve it below \ We now loop through all three axes, calculating the \ difference in 3D coordinates between this segment and \ the previous segment for xSegmentCoord, ySegmentCoord \ and zSegmentCoord .gseg6 LDA xSegmentCoordILo,X \ Set (A T) to the difference between the coordinate SEC \ of the previous segment and this one, starting with SBC xSegmentCoordILo,Y \ the low bytes STA T LDA xSegmentCoordIHi,X \ And then the high bytes SBC xSegmentCoordIHi,Y CLC \ Clear the C flag BPL gseg7 \ If the result in (A T) is positive, then jump to gseg7 SEC \ Set the C flag, to indicate that the result is \ negative .gseg7 PHP \ Store the C flag on the stack, which contains the sign \ bit of the result (0 for positive, 1 for negative), so \ we can use it to rotate the correct sign but into \ (A T) in the following ROR A \ Set (A T) = (A T) >> 1 ROR T \ \ making sure to retain the correct sign in bit 7 PLP \ Fetch the C flag from the stack, so it once again \ contains the correct sign for (A T) ROR A \ Set (A T) = (A T) >> 1 ROR T \ \ making sure to retain the correct sign in bit 7 STA V \ Set (V T) = (A T) \ \ So (V T) contains the difference in 3D coordinates, \ divided by 4, and with the correct sign retained LDX U \ Set X to the axis counter in U \ \ For clarity, the following comments will assume we are \ working with the x-axis LDA xSegmentCoordILo,Y \ Set xCoord1 = xSegmentCoord for previous segment CLC \ + (V T) ADC T \ STA xCoord1Lo,X \ starting with the low bytes LDA xSegmentCoordIHi,Y \ And then the high bytes ADC V STA xCoord1Hi,X INX \ Increment the axis counter in X CPX #3 \ If X = 3, we have done all three axes, so jump to BEQ gseg8 \ gseg8 STX U \ Store the incremented value in U, so this is the same \ as incrementing U LDX W \ Set X = W, which we set above to the segment offset \ for the current segment INY \ Increment Y to point to the next axis for the previous \ segment INX \ Increment X to point to the next axis for the current \ segment STX W \ Store the updated segment offset for the current \ segment in W JMP gseg6 \ Loop back to gseg6 to process the next axis .gseg8 \ By the time we get here, xCoord1 contains the 3D \ coordinates of the previous segment, plus a quarter \ of the vector from the previous segment to the current \ segment LDX #&FA \ Set X = &FA so the call to GetSegmentYawAngle uses \ xCoord1 JSR GetSegmentYawAngle \ Calculate the yaw angle and distance between the \ player's car and xCoord1, and store the results in \ the track segment list at the segment list pointer \ \ Also set (A K) = (L K) = the distance between the car \ and xCoord1 JSR GetObjPitchAngle-2 \ Calculate xCoord1's pitch angle, from the point \ of view of the player, returning it in A and LL \ \ If xCoord1 is not visible on-screen, the C flag is \ set, otherwise it will be clear BCS gseg9 \ If xCoord1 is not visible on-screen, jump to gseg9 \ to return from the subroutine \ If we get here then xCoord1 is visible, so we can \ store the results as our final entry in the track \ segment list LDX prevSegmentOffset \ Set X to the offset from xSegmentCoordILo of the \ previous segment's 3D coordinates, so the call to \ GetVergeAndMarkers uses the previous segment's verge \ data for our quarter segment's calculation LDA markersToDraw \ Store markersToDraw in markerNumber so we can restore STA markerNumber \ it after the call to GetVergeAndMarkers (so the call \ doesn't change the value of markersToDraw, as we \ don't want to try drawing markers with this \ quarter-size segment) JSR GetVergeAndMarkers \ Get the details for the previous segment's corner \ markers and verge marks and store them for this \ segment LDA markerNumber \ Retrieve the value of markersToDraw that we stored STA markersToDraw \ in markerNumber, so any marker calculations in the \ above call get ignored INC segmentListPointer \ Increment the segment list pointer as we just added a \ new entry to the track segment list .gseg9 RTS \ Return from the subroutine