Revs on the BBC Micro

# 3D objects: GetObjYawAngle (Part 2 of 4)

```       Name: GetObjYawAngle (Part 2 of 4)                            [Show more]
Type: Subroutine
Category: 3D objects
Summary: Calculate yaw angle for when |x-delta| > |z-delta|
Deep dive: Pitch and yaw angles
Context: See this subroutine in context in the source code
References: No direct references to this subroutine in this source file

.rotn5

\ This part is called from below, if we want to scale
\ the division

ASL RR                 \ Set (UU RR) = (UU RR) << 1
ROL UU

.rotn6

\ If we get here, then:
\
\   * (J I) = (A PP) = |x-delta|
\
\   * VV is the high byte of x-delta
\
\   * (H G) = (UU RR) = |z-delta|
\
\   * GG is the high byte of z-delta
\
\   * |x-delta| > |z-delta|
\
\ We now do the following division so we can use
\ trigonometry to calculate the yaw angle:
\
\   |z-delta| / |x-delta|
\
\ To get started, we shift both 16-bit values to the
\ left as far as possible, which we can do without
\ affecting the result as we are going to divide the two
\ values, so any mutual shifts will cancel each other
\ out in the division
\
\ Once that's done, we can drop the low bytes and just
\ divide the high bytes, which retains as much accuracy
\ as possible while avoiding the need for full 16-bit
\ division
\
\ So we keep shifting left until we get a 1 in bit 7 of
\ (A PP), as that's the larger of the two values

ASL PP                 \ Set (A PP) = (A PP) << 1
ROL A

BCC rotn5              \ If we just shifted a 0 out of the high byte of (A PP),
\ then we can keep shifting, so loop back to rotn6 to
\ keep shifting both values

ROR A                  \ We just shifted a 1 out of bit 7 of A, so reverse the
\ shift so A contains the correct high byte (we don't
\ care about the low byte any more)

\ So by this point, (A PP) and (UU RR) have both been
\ scaled by the same number of shifts

STA V                  \ Set V = A, the high byte of the scaled |x-delta|

LDA RR                 \ Set T = RR, the low byte of the scaled |z-delta|, to
STA T                  \ use for rounding the result in Divide8x8

LDA UU                 \ Set A = UU, the high byte of the scaled |z-delta|

CMP V                  \ If A = V then the high bytes of the scaled values
BEQ rotn9              \ match, so jump to rotn9, which deals with the case
\ when the xVector and zVector values are equal

\ We have scaled both values, so now for the division of
\ the high bytes

JSR Divide8x8          \ Set T = 256 * A / V
\       = 256 * |z-delta| / |x-delta|
\
\ using the lower byte of the |z-delta| numerator for
\ rounding

LDA #0                 \ Set II = 0 to use as the low byte for the final yaw
STA II                 \ angle

LDY T                  \ Set A = arctanY(T)
LDA arctanY,Y          \       = arctanY(|z-delta| / |x-delta|)
\
\ So this is the yaw angle of the object

STA M                  \ Store the yaw angle in M, to return from the
\ subroutine

LSR A                  \ Set (JJ II) = (A 0) >> 3
ROR II                 \             = A * 256 / 8
LSR A                  \             = A * 32
ROR II                 \             = arctanY(|z-delta| / |x-delta|) * 32
LSR A
ROR II
STA JJ

LDA VV                 \ If VV and GG have different signs, then so do x-delta
BMI rotn7

LDA #0                 \ Negate (JJ II)
SEC                    \
SBC II                 \ starting with the low bytes
STA II

LDA #0                 \ And then the high bytes
SBC JJ
STA JJ

.rotn7

LDA #64                \ Set A = 64, to add to the high byte below

BIT VV                 \ If x-delta is positive, jump to rotn8 to skip the
BPL rotn8              \ following instruction

\ If we get here then x-delta is negative

LDA #&C0               \ Set A = -64, to add to the high byte below

.rotn8

CLC                    \ Set (JJ II) = (JJ II) + (A 0)