Skip to navigation

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 aleady \ 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 \ already have, so when Y >= 8 we can simply jump to \ 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 \ Fall through into AddTempToPoint to add the anchor \ point to the (xTemp1, yTemp1, zTemp1) vector and store \ the result in (xPoint, yPoint, zPoint)