Skip to navigation

Aviator on the BBC Micro

3D geometry: SetObjPointCoords (Part 1 of 2)

Name: SetObjPointCoords (Part 1 of 2) [Show more] Type: Subroutine Category: 3D geometry Summary: Calculate the coordinate for a point within an object Deep dive: 3D objects Rotating and translating points in 3D space
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * FireGuns calls SetObjPointCoords * ProcessLine (Part 6 of 7) calls SetObjPointCoords * ProcessRunwayLine (Part 2 of 5) calls SetObjPointCoords

Arguments: GG The ID of the point to process and update matrixNumber The matrix to use in the calculation: * 0 = matrix 1 * 9 = matrix 2 * 18 = matrix 3 * 27 = matrix 4 objectAnchorPoint Point ID of the anchor point to which we add the final result to Returns: xPointHi etc. Point GG is set to the point's coordinate in 3D space showLine If the calculation overflows, then the coordinate does not fit within the boundaries of Aviator's 3D world, so bit 6 is set to indicate that the line containing this point should not be shown xTemp1Hi etc. The rotated vector from the anchor point to the object point
.SetObjPointCoords LDX GG \ Set X to the point ID whose coordinates we want to \ calculate LDY xObjectPoint,X \ Set PP to the point's anchor-relative x-coordinate STY PP \ from xObjectPoint LDY yObjectPoint,X \ Set QQ to the point's anchor-relative y-coordinate STY QQ \ from yObjectPoint LDY zObjectPoint,X \ Set RR (and Y) to the point's anchor-relative STY RR \ z-coordinate from zObjectPoint, which also contains \ the scale factor in bits 4 to 7 LDA shift4Right,Y \ Set UU (and A) to Y >> 4, to extract the scale factor STA UU \ from bits 4 to 7 of the zObjectPoint entry CMP #9 \ If the scale factor in A >= 9, set bit 7 of K so the ROR K \ result of the call to Multiply4x16 below is doubled, \ i.e. (G W) is doubled. This gives us an extra factor \ of 2 on top of the maximum 2^8 factor we would get by \ left-shifting the result (see part 2 for the scaling \ code) 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 .objp1 STA xTemp1Lo,X \ Zero the X-th byte of the six-byte coordinate block \ between xTemp1Lo and zTemp1Hi DEX \ Decrement the loop counter BPL objp1 \ Loop back until we have zeroed all six bytes \ We now do the matrix multiplication: \ \ [ xTemp1 ] [ m0 m1 m2 ] [ xObjectPoint ] \ [ yTemp1 ] = [ m3 m4 m5 ] x [ yObjectPoint ] \ [ zTemp1 ] [ m6 m7 m8 ] [ zObjectPoint ] \ \ 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 \ zObjectPoint, yObjectPoint and xObjectPoint \ \ 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 += zObjectPoint * m8 \ * zTemp1 += yObjectPoint * m7 \ * zTemp1 += xObjectPoint * m6 \ \ * yTemp1 += zObjectPoint * m5 \ * yTemp1 += yObjectPoint * m4 \ * yTemp1 += xObjectPoint * m3 \ \ * xTemp1 += zObjectPoint * m2 \ * xTemp1 += yObjectPoint * m1 \ * xTemp1 += xObjectPoint * 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 * xObjectPoint + m1 * yObjectPoint \ + m2 * zObjectPoint \ \ * yTemp1 = m3 * xObjectPoint + m4 * yObjectPoint \ + m5 * zObjectPoint \ \ * zTemp1 = m6 * xObjectPoint + m7 * yObjectPoint \ + m8 * zObjectPoint \ \ 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 .objp2 LDX #2 \ Set X = 2, to act as our inner loop counter that \ iterates through zObjectPoint, yObjectPoint and \ xObjectPoint (i.e. RR, QQ and PP) .objp3 LDY P \ Set Y = P, which is the number of the matrix element \ to multiply next LDA PP,X \ Set A = PP, QQ or RR (when X = 0, 1 or 2), which is \ the correct zObjectPoint, yObjectPoint or xObjectPoint \ to multiply next STA I \ Store A in I (this doesn't appear to be used) AND #%00001111 \ Set V = bits 0-3 of A, which removes the scale factor STA V \ in the case of zObjectPoint (the other points always \ fit into bits 0 to 3) BEQ objp5 \ If V = 0, jump to objp5 to move on to the next loop, \ as we already know the result of V * (S R) will be \ zero LDA matrix1Hi,Y \ Set S = P-th entry of matrix1Hi STA S 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 AND #1 \ If bit 0 of R is clear, then the matrix entry is BEQ objp4 \ positive, skip the following three instructions LDA V \ Bit 0 of R is set, which means this matrix entry is EOR #%10000000 \ negative, so set bit 7 of V to make it negative, to STA V \ give the result of the multiplication below the \ correct sign .objp4 STX Q \ Store the loop counter in X, so we can retrieve it \ after the call to Multiply4x16 JSR Multiply4x16 \ Call Multiply4x16 to calculate: \ \ (G W) = V * (S R) >> 8 if bit 7 of K = 0 \ \ (G W) = V * (S R) >> 7 if bit 7 of K = 1 \ \ K is only set to 1 if the scale factor is 9, in which \ case we effectively do one of the factors of 2 at this \ point (and the other 8 in part 2) 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 W \ Add (G W) to the xTemp1 coordinate, starting with the CLC \ low bytes ADC xTemp1Lo,Y STA xTemp1Lo,Y LDA G \ 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 += (G W) \ += V * (S R) \ += xObjectPoint * m0 \ \ which is the result we want for this element of the \ matrix multiplication .objp5 LDA P \ If P = matrixNumber then we have done all nine CMP matrixNumber \ calculations, so jump down to objp6 to apply the BEQ objp6 \ correct scale factor 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 zObjectPoint, yObjectPoint and xObjectPoint BPL objp3 \ 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 objp2 \ Jump back to objp2 to do the next calculation