Aviator on the BBC Micro

# 3D geometry: SetPointCoords

```       Name: SetPointCoords                                          [Show more]
Type: Subroutine
Category: 3D geometry
Summary: Calculate the coordinates for a point
Deep dive: Lines and points
Rotating and translating points in 3D space
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* ApplyFlightModel (Part 1 of 7) calls SetPointCoords
* ApplyFlightModel (Part 2 of 7) calls SetPointCoords
* ApplyFlightModel (Part 6 of 7) calls SetPointCoords
* FireGuns calls SetPointCoords
* ProcessHorizonLine calls SetPointCoords
* SetObjectCoords (Part 8 of 11) calls SetPointCoords

Arguments:

GG                   The ID of the point to process

matrixNumber         The matrix to use in the calculation:

* 0 = matrix 1

* 9 = matrix 2

* 18 = matrix 3

* 27 = matrix 4

xPointHi  etc.       The point's coordinates before rotation

Returns:

xPointHi  etc.       The point's coordinates after rotation

xTemp1Hi  etc.       The point's coordinates after rotation

.SetPointCoords

LDX GG                 \ Set X to the point ID whose coordinates we want to
\ calculate

LDA xPointLo,X         \ Set (SS PP) to the point's x-coordinate
STA PP
LDA xPointHi,X
STA SS

LDA yPointLo,X         \ Set (TT QQ) to the point's y-coordinate
STA QQ
LDA yPointHi,X
STA TT

LDA zPointLo,X         \ Set (UU RR) to the point's z-coordinate
STA RR
LDA zPointHi,X
STA UU

LDX #5                 \ We now zero (xTemp1, yTemp1, zTemp1), which is stored
\ in six bytes to give us three 16-bit coordinate values
\ (from xTemp1Lo to zTemp1Hi), so set a counter in X to
\ count the bytes

LDA #0                 \ Set A = 0 to use as our zero

.pcrd1

STA xTemp1Lo,X         \ Zero the X-th byte of the six-byte coordinate block
\ between xTemp1Lo and zTemp1Hi

DEX                    \ Decrement the loop counter

BPL pcrd1              \ Loop back until we have zeroed all six bytes

\ We now do the matrix multiplication:
\
\   [ xTemp1 ]     [ m0 m1 m2 ]   [ xPoint ]
\   [ yTemp1 ]  =  [ m3 m4 m5 ] x [ yPoint ]
\   [ zTemp1 ]     [ m6 m7 m8 ]   [ zPoint ]
\
\ We do this in three loops of three, using an outer and
\ inner loop. We set two loop counters, VV and X, for
\ the outer and inner loops respectively. They both
\ iterate through 2, 1 and 0, with VV iterating through
\ zTemp1, yTemp1 and xTemp1, and X iterating through
\ zPoint, yPoint and xPoint
\
\ We also iterate a counter in P for the matrix entries,
\ which counts down from m8 to m0, decreasing by 1 on
\ each iteration
\
\ All the iterators count backwards, so the calculations
\ in order are:
\
\   * zTemp1 += zPoint * m8
\   * zTemp1 += yPoint * m7
\   * zTemp1 += xPoint * m6
\
\   * yTemp1 += zPoint * m5
\   * yTemp1 += yPoint * m4
\   * yTemp1 += xPoint * m3
\
\   * xTemp1 += zPoint * m2
\   * xTemp1 += yPoint * m1
\   * xTemp1 += xPoint * m0
\
\ Or, to switch it around the othee way and plug in the
\ initial value of (xTemp1, yTemp1, zTemp1) = (0, 0, 0),
\ we get:
\
\   * xTemp1 = m0 * xPoint + m1 * yPoint + m2 * zPoint
\
\   * yTemp1 = m3 * xPoint + m4 * yPoint + m5 * zPoint
\
\   * zTemp1 = m6 * xPoint + m7 * yPoint + m8 * zPoint
\
\ which gives us the matrix multiplication that we want
\ to calculate

LDA matrixNumber       \ Set P = matrixNumber + 8
CLC                    \
ADC #8                 \ In the following loop, P counts down from m8 to m0,
STA P                  \ which we implement as an index that counts down from
\ matrixNumber + 8 to matrixNumber, so that it iterates
\ through the correct matrix table
\
\ This works because matrixNumber contains 0 for matrix
\ 1, 9 for matrix 2 and so on, and each matrix table,
\ such as matrix1Lo, contains 9 entries

LDA #2                 \ Set VV = 2, to act as our outer loop counter that
STA VV                 \ iterates through zTemp1, yTemp1 and xTemp1

.pcrd2

LDX #2                 \ Set X = 2, to act as our inner loop counter that
\ iterates through zPoint, yPoint and xPoint

.pcrd3

LDY P                  \ Set Y = P, which is the number of the matrix element
\ to multiply next

LDA matrix1Hi,Y        \ Set S = P-th entry of matrix1Hi
STA S

BNE pcrd4

LDA matrix1Lo,Y        \ If the P-th entry of matrix1Lo is < 5, jump to pcrd5
CMP #5                 \ to move on to the next loop
BCC pcrd5

.pcrd4

LDA matrix1Lo,Y        \ Set R = P-th entry of matrix1Lo
STA R                  \
\ so now (S R) is the 16-bit matrix element that we want
\ to multiply

LDA PP,X               \ Set I = PP, QQ or RR (when X = 0, 1 or 2), which is
STA I                  \ the correct zPointLo, yPointLo or xPointLo to multiply
\ next

LDA SS,X               \ Set J = SS, TT or UU (when X = 0, 1 or 2), which is
STA J                  \ the correct zPointHi, yPointHi or xPointHi to multiply
\ next so now (J I) is the 16-bit point coordinate that
\ we want to multiply

LDA #0                 \ Set K = 0, so Multiply16x16Mix doesn't negate the
STA K                  \ result

STX Q                  \ Store the loop counter in X, so we can retrieve it
\ after the call to Multiply16x16Mix

JSR Multiply16x16Mix   \ Call Multiply16x16Mix to calculate:
\
\   (H G) = (J I) * (S R) >> 16

LDX Q                  \ Restore the value of X

LDY VV                 \ Fetch the outer loop counter from VV, which points to
\ the relevant xTemp1, yTemp1 or zTemp1 coordinate

LDA G                  \ Add (H G) to the xTemp1 coordinate, starting with the
CLC                    \ low bytes
STA xTemp1Lo,Y

LDA H                  \ And then the high bytes, so we have the following (if
ADC xTemp1Hi,Y         \ we are working with xTemp1 and m0, for example):
STA xTemp1Hi,Y         \
\   xTemp1 += (H G)
\         += (J I) * (S R)
\         += xPoint * m0
\
\ which is the result we want for this element of the
\ matrix multiplication

BVC pcrd5

LDA #%01000000         \ The addition overflowed for this axis, so set bit 6 of
STA showLine           \ showLine so the line containing this point is marked
\ as being hidden

.pcrd5

LDY P                  \ If P = matrixNumber then we have done all nine
CPY matrixNumber       \ calculations, so jump down to objp6 to update the
BEQ pcrd6              \ point's coordinates with the result

DEC P                  \ Otherwise we have more calculations to do, so
\ decrement P to point to the next matrix entry

DEX                    \ Decrement the inner loop counter to work our way
\ through zPoint, yPoint and xPoint

BPL pcrd3              \ Loop back until we have worked through all three
\ anchor-relative points

DEC VV                 \ Decrement the outer loop counter to work our way
\ through zTemp1, yTemp1 and xTemp1

JMP pcrd2              \ Jump back to objp2 to do the next calculation

.pcrd6

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

\ Fall through into CopyTempToPoint to copy the result
\ from (xTemp1, yTemp1, zTemp1) to (xPoint, yPoint,
\ zPoint)
```