Aviator on the BBC Micro

# 3D geometry: SetObjPointCoords (Part 2 of 2)

```       Name: SetObjPointCoords (Part 2 of 2)                         [Show more]
Type: Subroutine
Category: 3D geometry
Summary: Apply the correct scale factor to the matrix multiplication
Deep dive: 3D objects
Rotating and translating points in 3D space
Context: See this subroutine in context in the source code
References: No direct references to this subroutine in this source file

.objp6

\ We now want to apply the scale factor that we
\ extracted into UU above. The scale factor is given as
\ a power of 2, so a scale factor of n means we scale
\ the result by 2^n, which we can do by shifting left
\ by n places (where n is in the range 0 to 8)
\
\ Note that n can also be 9, in which case we already
\ doubled the result in part 1, so by this point we only
\ need to shift a maximum of 8 places
\
\ Note also that we are scaling up 16-bit numbers, so
\ in order to capture these scaled-up values, we add a
\ third byte to the significant end, giving us a 24-bit
\ number to shift, and we take the top two bytes as our
\ final result, discarding the least significant byte
\
\ This means the result we end up with is divided by
\ another 256 but fits into two bytes

LDX #2                 \ Set X = 2 to act as a loop counter, to iterate through
\ 2, 1 and 0, which we use to work through zTemp1,
\ yTemp1 and xTemp1, scaling each one separately
\
\ The comments below refer to xTemp1, for simplicity

.objp7

LDY UU                 \ Set Y = UU = %0000ZZZZ, which is our scale factor

BEQ objp10             \ If UU = 0, then the scale factor is 2^0, or 1, so
\ there is no scaling to do, so jump to objp10 to drop
\ the least significant byte without any shifting

CPY #8                 \ If Y >= 8 then we can skip doing 8 shifts as the
BCS objp9              \ result is already correct. To see this, consider the
\ process below, which creates (0 xTemp1Hi xTemp1Lo) and
\ shifts it left by the number of places, which would be
\ this if Y = 8:
\
\   (0 xTemp1Hi xTemp1Lo) << 8 = (xTemp1Hi xTemp1Lo 0)
\
\ from which we would then drop the least significant
\ byte to give (xTemp1Hi xTemp1Lo)... which is what we
\ objp9 to move on to the next axis
\
\ (As noted above, if Y = 9 then we already doubled the
\ result in part 1, so the above approach works for both
\ Y = 8 and 9)

LDA xTemp1Lo,X         \ Set P to the low byte of xTemp1
STA P

LDA #0                 \ Set R = 0 to act as the new highest byte in our 24-bit
STA R                  \ number

LDA xTemp1Hi,X         \ Set A to the high byte of xTemp1, so we now have the
\ following 24-bit number:
\
\   (R A P) = (0 xTemp1Hi xTemp1Lo)

BPL objp8              \ If the high byte of xTemp1 is positive, skip the
\ following instruction

DEC R                  \ xTemp1Hi is negative, so decrement R to &FF so (R A P)
\ is a correctly signed 24-bit negative number

\ We now shift (R A P) left by Y places (where Y is in
\ the range 1 to 7)

.objp8

ASL P                  \ Set (R A P) = (R A P) << 1
ROL A
ROL R

DEY                    \ Decrement the shift counter in Y

BNE objp8              \ Loop back to objp8 until we have shifted (R A P) left
\ by Y places

STA xTemp1Lo,X         \ Set xTemp1 = (R A)
LDA R                  \
STA xTemp1Hi,X         \ so we drop the least significant byte, as discussed
\ above

.objp9

DEX                    \ Decrement the counter in X so we work through zTemp1,
\ yTemp1 and xTemp1

BPL objp7              \ Loop back to objp7 until we have processed all three
\ axes

BMI objp12             \ Jump to objp12 to finish off (this BMI is effectively
\ a JMP as X is now negative)

.objp10

\ If we get here then the scale factor is 0, so we can
\ simply drop the least significant byte without any
\ shifting, as discussed above

LDA #0                 \ Set (R A) = (0 xTemp1Hi)
STA R
LDA xTemp1Hi,X

BPL objp11             \ If xTemp1Hi is positive, skip the next instruction

DEC R                  \ xTemp1Hi is negative, so decrement R to &FF so (R A)
\ is a 16-bit negative number

.objp11

STA xTemp1Lo,X         \ Set xTemp1 = (R A)
LDA R
STA xTemp1Hi,X

JMP objp9              \ Jump back to objp9 to move on to the next axis (i.e.
\ yTemp1 or zTemp1)

.objp12

\ Our vector in (xTemp1, yTemp1, zTemp1) is now scaled
\ properly, so it's time for the addition:
\
\   [ xPoint ]   [ xAnchor ]   [ xTemp1 ]
\   [ yPoint ] = [ yAnchor ] + [ yTemp1 ]
\   [ zPoint ]   [ zAnchor ]   [ zTemp1 ]

LDX GG                 \ Set X to the point ID whose coordinates we want to
\ calculate, so the original point is updated with the
\ final result

LDY objectAnchorPoint  \ Set Y to the point ID of the object's anchor point