Skip to navigation

Lander on the Acorn Archimedes

Maths (Geometry): GetDotProduct

Name: GetDotProduct [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Calculate the dot product of two 3D vectors Deep dive: Drawing 3D objects
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * DrawObject (Part 3 of 5) calls GetDotProduct * MultiplyVectorByMatrix calls GetDotProduct

Calculate the dot product of the 3D vectors at R0 and R2 as follows: [ R0 ] [ R2 ] R3 = [ R0+4 ] . [ R2+4 ] = (R0 * R2) + (R0+4 * R2+4) + (R0+8 * R2*8) [ R0+8 ] [ R2+8 ] and set the flags according to the result. R2 is updated to the next vector in memory, so repeated calls will work through the following multiplication, returning one row at a time: [ R2 R2+4 R2+8 ] [ R0 ] [ R2+12 R2+16 R2+20 ] . [ R0+4 ] [ R2+24 R2+28 R2+32 ] [ R0+8 ] See the MultiplyVectorByMatrix routine to see this calculation in use.
Arguments: R0 The address of the first vector R2 The address of the second vector
Returns: R2 Updated to the address of the next R2 vector R3 The dot product Flags Set according to the result in R3
.GetDotProduct LDR R4, [R2], #4 \ Set R4 to the x-coordinate of R2 (let's \ call it xR2), and increment R2 to point to \ the y-coordinate of R2 LDR R5, [R0] \ Set R5 to the x-coordinate of R0 (let's \ call it xR0) \ We now calculate R3 = R4 * R5 using the \ shift-and-add multiplication algorithm EOR R7, R4, R5 \ Set the sign of the result in R7 TEQ R4, #0 \ Set R4 = 4 * |R4| RSBMI R4, R4, #0 MOVS R4, R4, LSL #2 TEQ R5, #0 \ Set R5 = 2 * |R5| RSBMI R5, R5, #0 MOV R5, R5, LSL #1 AND R4, R4, #&FE000000 \ Zero all but the top byte of R4, ensuring ORR R4, R4, #&01000000 \ that bit 0 of the top byte is set so the \ value of the fractional part is set to 0.5 MOV R3, #0 \ Set R3 = 0 to use for building the sum in \ our shift-and-add multiplication result .dotp1 MOV R5, R5, LSR #1 \ If bit 0 of R5 is set, add R5 to the ADDCS R3, R3, R5 \ result in R3, shifting R5 to the right MOVS R4, R4, LSL #1 \ Shift R4 left by one place BNE dotp1 \ Loop back if R4 is non-zero MOV R3, R3, LSR #1 \ Set R3 = R3 / 2 TEQ R7, #0 \ Apply the sign from R7 to R3 to get the RSBMI R3, R3, #0 \ final result, so: \ \ R3 = R4 * R5 \ = xR0 * xR2 LDR R4, [R2], #4 \ Set R4 to the y-coordinate at R2+4 (let's \ call it yR2), and increment R2 to point to \ the z-coordinate of R2 LDR R5, [R0, #4] \ Set R5 to the y-coordinate at R0+4 (let's \ call it yR0) EOR R7, R4, R5 \ Set R6 = R4 * R5 using the same algorithm TEQ R4, #0 \ as above RSBMI R4, R4, #0 \ MOVS R4, R4, LSL #2 \ This is the first part of the algorithm TEQ R5, #0 RSBMI R5, R5, #0 MOV R5, R5, LSL #1 AND R4, R4, #&FE000000 ORR R4, R4, #&01000000 MOV R6, #0 .dotp2 MOV R5, R5, LSR #1 \ This is the second part of the algorithm, ADDHS R6, R6, R5 \ so we now have: MOVS R4, R4, LSL #1 \ BNE dotp2 \ R6 = R4 * R5 MOV R6, R6, LSR #1 \ = yR0 * yR2 TEQ R7, #0 RSBMI R6, R6, #0 ADD R3, R3, R6 \ Set R3 = R3 + R6 \ = xR0 * xR2 + yR0 * yR2 LDR R4, [R2], #4 \ Set R4 to the z-coordinate at R2+8 (let's \ call it zR2), and increment R2 to point to \ the next coordinate at R2+12 LDR R5, [R0, #8] \ Set R5 to the z-coordinate at R0+8 (let's \ call it zR0) EOR R7, R4, R5 \ Set R6 = R4 * R5 using the same algorithm TEQ R4, #0 \ as above RSBMI R4, R4, #0 \ MOVS R4, R4, LSL #2 \ This is the first part of the algorithm TEQ R5, #0 RSBMI R5, R5, #0 MOV R5, R5, LSL #1 AND R4, R4, #&FE000000 ORR R4, R4, #&01000000 MOV R6, #0 .dotp3 MOV R5, R5, LSR #1 \ This is the second part of the algorithm, ADDHS R6, R6, R5 \ so we now have: MOVS R4, R4, LSL #1 \ BNE dotp3 \ R6 = R4 * R5 MOV R6, R6, LSR #1 \ = zR0 * zR2 TEQ R7, #0 RSBMI R6, R6, #0 ADDS R3, R3, R6 \ Set R3 = R3 + R6 \ = xR0 * xR2 + yR0 * yR2 + zR0 * zR2 \ \ which is the result we want \ \ We also set the flags depending on the \ result MOV PC, R14 \ Return from the subroutine