Skip to navigation

Lander on the Acorn Archimedes

Drawing triangles: DrawTriangle (Part 5 of 11)

Name: DrawTriangle (Part 5 of 11) [Show more] Type: Subroutine Category: Drawing triangles Summary: Draw a triangle with a horizontal edge between (x1, y1) and (x2, y2) Deep dive: Drawing triangles
Context: See this subroutine in context in the source code References: No direct references to this subroutine in this source file
.trin16 \ If we get here then y1 = y2, so (x1, y1) \ and (x2, y2) share the same y-coordinate \ and the triangle has a horizontal edge \ between (x1, y1) and (x2, y2) SUBS R9, R3, R5 \ Set R9 = R3 - R5 \ = y2 - y3 \ \ So this is the vertical distance between \ (x2, y2) and (x3, y3), i.e. the delta \ y-coordinate between the two points \ \ We know this is positive because y2 >= y3 \ \ We also know that y1 = y2, so: \ \ R9 = y2 - y3 \ = y1 - y3 LDMEQIA R13!, {PC} \ If R9 = 0 then y2 = y3, which means all \ three corners share the same y-coordinate \ and are at the same height on-screen \ \ This means there is no triangle to draw, \ so return from the subroutine SUBS R14, R0, R4 \ Set R14 = R0 - R4 \ = x1 - x3 \ \ So this is the vertical distance between \ (x1, y1) and (x3, y3), i.e. the delta \ x-coordinate between the two points \ \ This will be negative if the line from \ (x1, y1) to (x3, y3) slopes up and to the \ right, or negative if the line slopes up \ and to the left RSBMI R14, R0, R4 \ If R14 is negative, set R14 = x1 - x3, so \ we have the following: \ \ R14 = |x1 - x3| CMP R14, #64 \ If either R14 >= 64 or R9 >= 64, then at CMPLO R9, #64 \ least one of these is true: BHS trin17 \ \ R14 = |x1 - x3| >= 64 \ \ R9 = (y1 - y3) >= 64 \ \ so jump to trin17 to calculate the slope \ using the shift-and-subtract algorithm LDR R10, divisionTableAddr \ Set R10 to the address of the division \ tables ADD R10, R10, R14, LSL #8 \ Set R10 to the address of the division \ table containing n / R14, for n = 0 to 63 \ \ This works because each division table \ contains 64 words, or 256 bytes, so the \ address of table n / d is: \ \ divisionTable + d * 256 LDR R6, [R10, R9, LSL #2] \ Set R6 to the R9-th word in the division \ table containing n / R14, so this \ calculates the following: \ \ R6 = R9 / R14 \ \ = (y3 - y1) / |x3 - x1| B trin19 \ Jump to trin19 to skip the following and \ keep going .trin17 \ If we get here then at least one of these \ is true: \ \ R14 = |x1 - x3| >= 64 \ \ R9 = (y1 - y3) >= 64 \ \ We now calculate R2 = R9 / R14 using the \ shift-and-subtract division algorithm MOV R9, R9, LSL #16 \ First we scale R9 up as far as we can, to \ make the result as accurate as possible MOV R6, #0 \ Set R6 = 0 to contain the result MOV R10, #&80000000 \ Set bit 31 of R10 so we can shift it to \ the right in each iteration, using it as a \ counter .trin18 MOVS R14, R14, LSL #1 \ Shift R14 left, moving the top bit into \ the C flag CMPCC R14, R9 \ If we shifted a 0 out of the top of R14, \ test for a possible subtraction SUBCS R14, R14, R9 \ If we shifted a 1 out of the top of R14 or ORRCS R6, R6, R10 \ R14 >= R9, then do the subtraction: \ \ R14 = R14 - R9 \ \ and set the relevant bit in the result \ (i.e. apply the set bit in R10 to the \ result in R6) MOVS R10, R10, LSR #1 \ Shift R10 to the right, moving bit 0 into \ the C flag BCC trin18 \ Loop back until we shift the 1 out of the \ right end of R10 (after 32 shifts) \ So we now have the following result: \ \ R6 = R9 / R14 \ \ = (y3 - y1) / |x3 - x1| .trin19 CMP R4, R0 \ If R4 - R0 < 0 then: RSBMI R6, R6, #0 \ \ x3 - x1 < 0 \ \ so negate R6 to give R6 the correct sign \ for the following calculation: \ \ R6 = (y3 - y1) / (x3 - x1) \ \ So R6 contains the slope of the first side \ of the triangle, from (x1, y1) to (x3, y3) \ We now calculate the slope for the second \ side of the triangle, from (x2, y2) to \ (x3, y3), as follows: \ \ R7 = (y2 - y3) / (x2 - x3) SUB R9, R3, R5 \ Set R9 = R3 - R5 \ = y2 - y3 SUBS R14, R2, R4 \ Set R14 = R4 - R2 \ = x3 - x2 RSBMI R14, R2, R4 \ If R14 is negative, set R4 = x2 - x3, so \ we have the following: \ \ R14 = |x3 - x2| CMP R14, #64 \ If either R14 >= 64 or R9 >= 64, then at CMPLO R9, #64 \ least one of these is true: BHS trin20 \ \ R14 = |x3 - x2| >= 64 \ \ R9 = (y2 - y3) >= 64 \ \ so jump to trin20 to calculate the slope \ using the shift-and-subtract algorithm LDR R10, divisionTableAddr \ Set R10 to the address of the division \ tables ADD R10, R10, R14, LSL #8 \ Set R10 to the address of the division \ table containing n / R14, for n = 0 to 63 \ \ This works because each division table \ contains 64 words, or 256 bytes, so the \ address of table n / d is: \ \ divisionTable + d * 256 LDR R7, [R10, R9, LSL #2] \ Set R7 to the R9-th word in the division \ table containing n / R14, so this \ calculates the following: \ \ R7 = R9 / R14 \ \ = (y2 - y3) / |x3 - x2| B trin22 \ Jump to trin22 to skip the following and \ keep going .trin20 \ If we get here then at least one of these \ is true: \ \ R14 = |x3 - x2| >= 64 \ \ R9 = (y2 - y3) >= 64 \ \ We now calculate R2 = R9 / R14 using the \ shift-and-subtract division algorithm MOV R9, R9, LSL #16 \ First we scale R9 up as far as we can, to \ make the result as accurate as possible MOV R7, #0 \ Set R7 = 0 to contain the result MOV R10, #&80000000 \ Set bit 31 of R10 so we can shift it to \ the right in each iteration, using it as a \ counter .trin21 MOVS R14, R14, LSL #1 \ Shift R14 left, moving the top bit into \ the C flag CMPCC R14, R9 \ If we shifted a 0 out of the top of R14, \ test for a possible subtraction SUBCS R14, R14, R9 \ If we shifted a 1 out of the top of R14 or ORRCS R7, R7, R10 \ R14 >= R9, then do the subtraction: \ \ R14 = R14 - R9 \ \ and set the relevant bit in the result \ (i.e. apply the set bit in R10 to the \ result in R7) MOVS R10, R10, LSR #1 \ Shift R10 to the right, moving bit 0 into \ the C flag BCC trin21 \ Loop back until we shift the 1 out of the \ right end of R10 (after 32 shifts) \ So we now have the following result: \ \ R7 = R9 / R14 \ \ = (y2 - y3) / |x3 - x2| .trin22 CMP R4, R2 \ If R4 - R2 < 0 then: RSBMI R7, R7, #0 \ \ x3 - x2 < 0 \ \ so negate R7 to give R7 the correct sign \ for the following calculation: \ \ R7 = (y2 - y3) / (x3 - x2) \ \ So R7 contains the slope of the second \ side of the triangle, from (x2, y2) to \ (x3, y3) SUB R9, R3, R5 \ Set R9 = R3 - R5 \ = y2 - y3 MOV R4, R0, LSL #16 \ Set R4 = R0 << 16 \ = x1 << 16 \ \ We scale up R4 so that it can contain a \ fractional result - we will treat the \ bottom 16 bits as the fraction, so \ R4 >> 16 gives us the integral part \ \ We use R4 as the x-coordinate of the left \ end of the horizontal line to draw (after \ swapping the ends below if necessary) MOV R5, R2, LSL #16 \ Set R5 = R0 << 16 \ = x2 << 16 \ \ We scale up R5 so that it can contain a \ fractional result - we will treat the \ bottom 16 bits as the fraction, so \ R5 >> 16 gives us the integral part \ \ We use R5 as the x-coordinate of the right \ end of the horizontal line to draw (after \ swapping the ends below if necessary) ORR R4, R4, #&8000 \ Set the top bit of the fractional parts of ORR R5, R5, #&8000 \ both R4 and R5 (so that's 0.5) CMP R4, R5 \ If R4 >= R5 then x1 >= x2, so we need to MOVHS R14, R6 \ swap R6 and R7, and swap R4 and R5, to MOVHS R6, R7 \ ensure that R4 is the left end of the line MOVHS R7, R14 \ and R5 is the right end, and that the MOVHS R14, R4 \ slopes are swapped accordingly MOVHS R4, R5 MOVHS R5, R14 B trin14 \ Jump to trin14 in part 4 to draw the \ triangle