# 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                  \

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                  \

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)
STA xCoord1Lo,X        \ starting with the low bytes

LDA xSegmentCoordIHi,Y \ And then the high bytes
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
```