Revs on the BBC Micro

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

```       Name: GetObjYawAngle (Part 4 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

.rotn13

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

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

.rotn14

\ If we get here, then:
\
\   * (H G) = (SS PP) = |x-delta|
\
\   * VV is the high byte of x-delta
\
\   * (J I) = (A 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:
\
\   |x-delta| / |z-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 RR), as that's the larger of the two values

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

BCC rotn13             \ If we just shifted a 0 out of the high byte of (A RR),
\ then we can keep shifting, so loop back to rotn13 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 RR) and (SS PP) have both been
\ scaled by the same number of shifts

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

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

LDA SS                 \ Set A = SS, the high byte of the scaled |x-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 * |x-delta| / |z-delta|
\
\ using the lower byte of the |x-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(|x-delta| / |z-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(|x-delta| / |z-delta|) * 32
LSR A
ROR II
STA JJ

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

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

.rotn15

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

BIT GG                 \ If z-delta is positive, jump to rotn16 to skip the
BPL rotn16             \ following instruction

\ If we get here then z-delta is negative

LDA #&80               \ Set A = -128, to add to the high byte below

.rotn16

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