Skip to navigation

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
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 other 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 ADC xTemp1Lo,Y 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)