Revs on the BBC Micro

# Drawing the track: DrawSegmentEdge (Part 2 of 7)

```       Name: DrawSegmentEdge (Part 2 of 7)                           [Show more]
Type: Subroutine
Category: Drawing the track
Summary: Set up the edge's gradient
Deep Dive: Drawing the track verges
Context: See this subroutine in context in the source code
References: No direct references to this subroutine in this source file

This part calculates the edge's gradient in terms of the change in yaw and
pitch angles, and stores them in SS and TT, with SS containing the yaw delta,
and TT containing the pitch delta.

.dver3

LDA RR                 \ Set A = RR - N
SEC
SBC N

STA WW                 \ Set WW = A
\
\ So WW contains the current edge's pitch angle minus
\ the previous edge's pitch angle, so:
\
\   * WW is positive if the current pitch angle is
\     greater than the previous pitch angle, so the
\     current edge is higher up the screen, so the edge
\     is moving up the screen
\
\   * WW is negative if the current pitch angle is
\     less than the previous pitch angle, so the
\     current edge is lower down the screen, so the edge
\     is moving down the screen

BPL dver4              \ If A is positive, jump to dver4

LDA #0                 \ Set A = -WW
SEC                    \       = -A
SBC WW                 \
\ So A is now positive, i.e. A = |RR - N|

.dver4

STA TT                 \ Set TT = A
\        = |RR - N|
\
\ So TT contains the difference in pitch angle between
\ the previous edge and the current edge, so let's call
\ it dPitch:
\
\   TT = |dPitch|

LDA GG                 \ If bits 6 and 7 of GG are clear, then both this and
AND #%11000000         \ the previous segment's verge edges were on-screen, so
BEQ dver9              \ jump to dver9 to calculate the difference in yaw
\ angles in SS

\ If we get here then one of the previous segment's
\ verge edges were off-screen, so we need to interpolate
\ the angles to calculate where the edge meets the
\ screen edge

LDY thisYawIndex       \ Set Y to the index of the yaw angle in the track
\ segment list for this verge

LDX prevYawIndex       \ Set X to the index of the yaw angle in the track
\ segment list for the segment from the previous call

LDA xVergeRightLo,Y    \ Set (VV T) to the difference in yaw angle between the
SEC                    \ current segment and the previous segment, starting
SBC xVergeRightLo,X    \ with the low bytes
STA T

LDA xVergeRightHi,Y    \ And then the high bytes
SBC xVergeRightHi,X
STA VV

\ This also sets the sign of VV as follows:
\
\   * VV is positive if the previous yaw angle is less
\     than the current yaw angle, so the edge is moving
\     from left to right
\
\   * VV is negative if the previous yaw angle is
\     greater than the current yaw angle, so the edge is
\     moving from right to left

JSR Absolute16Bit      \ Set (A T) = |A T|
\
\ So (A T) contains the difference in yaw angle between
\ the previous edge and the current edge, so let's call
\ it dYaw:
\
\   (A T) = |dYaw|

\ We now scale (A T) and TT, scaling (A T) up while
\ scaling TT down, up to a maximum of two shifts up and
\ down, as follows:
\
\   * If |dYaw| >= 64, |dPitch| / 4
\
\   * If |dYaw| >= 32, |dYaw| * 2, |dPitch| / 2
\
\   * If |dYaw| < 16, |dYaw| * 4
\
\ This scales |dYaw| to be as large as possible while
\ simultaneously making |dPitch| as small as possible

CMP #64                \ If A >= 64, jump to dver5 to divide TT by 4
BCS dver5

ASL T                  \ Set (A T) = (A T) * 2
ROL A                  \           = |dYaw| * 2

CMP #64                \ If A >= 64, jump to dver6 to divide TT by 2
BCS dver6

ASL T                  \ Set (A T) = (A T) * 2
ROL A                  \           = |dYaw| * 4

BPL dver7              \ Jump to dver7 (this BPL is effectively a JMP as bit 7
\ of A will never be set, as the maximum value of A
\ before the last ROR was 63, and 63 << 1 = 126, which
\ has bit 7 clear)

.dver5

LSR TT                 \ Set TT = TT / 2
\        = |dPitch| / 2

.dver6

LSR TT                 \ Set TT = TT / 2
\        = |dPitch| / 2

.dver7

STA SS                 \ Set SS = A
\        = scaled |dYaw|

LDA VV                 \ If vergeOnScreenEdge = &FF, then this sets VV to ~VV,
EOR vergeOnScreenEdge  \ which flips bit 7 (which we will use later)
STA VV

LDA SS                 \ Set A = SS

JMP dver10             \ Jump to dver10 to finish setting up SS and TT

.dver8

JMP dver28             \ Jump to dver28 (this is used as a way for branch
\ instructions to jump to dver28, when it is too far
\ for a branch instruction to reach

.dver9

\ If we get here then both the previous and current
\ verge edges are on-screen, so we need to set SS to the
\ difference in yaw angle between the previous and
\ current edges
\
\ Note that we added 128 to each yaw angle to convert
\ them in the range 0 to 255 (rather than -128 to +127)
\ so the subtraction will set the C flag correctly

LDA M                  \ Set A = M - W
SEC                    \
SBC W                  \ So A contains the difference in yaw angle between the
\ previous edge and the current edge, so let's call it
\ dYaw

ROR VV                 \ Rotate the C flag into bit 7 of VV, so bit 7 is set if
\ M >= W, or clear if M < W

BMI dver10             \ If A is negative, jump to dver10 to finish setting up
\ SS and TT

EOR #&FF               \ Negate A using two's complement, so A is negative,
CLC                    \ i.e. A = -|A|

\ We now fall through into dver10 to set SS to A, which
\ contains -|M - W|, or -|dYaw|

.dver10

STA SS                 \ Set SS = A

BNE dver11             \ If A is non-zero, jump to dver11

ORA TT                 \ A is zero, so this sets A to TT

BEQ dver8              \ If A is zero (which means both SS and TT are zero),
\ jump to dver28 via dver8 to clean up and return from
\ the subroutine

\ By this point, we have the following:
\
\   * SS = the scaled yaw delta along the edge to draw
\          (scaled to be as large as possible)
\
\   * TT = the scaled pitch delta along the edge to draw
\          (scaled to be as small as possible)
\
\   * VV = the left-right direction of the edge
\
\     * Positive = left to right
\
\     * Negative = right to left
\
\   * WW = the up-down direction of the edge
\
\     * Positive = line is heading up the screen
\
\     * Negative = line is heading down the screen
\
\ So SS and TT are set to the gradient of the edge that
\ we are drawing, and WW and VV are set to the direction
\ of the edge
```