Skip to navigation

Lander on the Acorn Archimedes

3D objects: DrawObject (Part 5 of 5)

Name: DrawObject (Part 5 of 5) [Show more] Type: Subroutine Category: 3D objects Summary: Draw each of the object's faces Deep dive: Drawing 3D objects Object blueprints Screen memory in the Archimedes
Context: See this subroutine in context in the source code References: No direct references to this subroutine in this source file
.dobj4 CMP R3, #0 \ If R3 is positive then the face is facing BPL dobj5 \ away from us and isn't visible, so jump to \ dobj5 to skip drawing the face \ We now calculate the colour of the face, \ setting the brightness according to the \ direction that the face is pointing (the \ light source is directly above and \ slightly to the left) LDMIA R9, {R4-R7} \ Set R4, R5, R6, R7 to the fourth, fifth, \ sixth and seventh words of face data, \ which contain the numbers of the vertices \ that make up the face (in R4, R5 and R6), \ and the face colour (in R7] ADD R10, R11, #vertexProjected \ Set R10 to the address of vertexProjected \ \ For each vertex we wrote two coordinates \ to vertexProjected, with the first being \ the face's projected coordinates, so this \ sets R10 to the address of the first \ projected coordinate's pixel x-coordinate, \ i.e. the pixel coordinate for the first \ object vertex LDR R1, [R11, #yVertex] \ Set R1 to yVertex, the y-coordinate of the \ rotated normal LDR R0, [R11, #xVertex] \ Set R0 to xVertex, the x-coordinate of the \ rotated normal RSB R1, R1, #&80000000 \ Set R1 = (&80000000 - R1) >> 28 MOV R1, R1, LSR #28 \ = (&80000000 - yVertex) >> 28 \ \ So R1 is in the range 0 to 8 and is \ bigger when the normal is pointing more \ vertically (i.e. when the normal vector \ has a negative y-coordinate with a larger \ magnitude, as the y-axis points down the \ screen) \ \ So a bigger, more negative R1 means \ brighter colours CMP R0, #0 \ If R0 is negative then the normal is ADDMI R1, R1, #1 \ pointing more towards the left then the \ right, so increment R1 to make the face \ slightly brighter (as the light source is \ a little bit to the left) SUBS R1, R1, #5 \ Set R1 = max(0, R1 - 5) MOVMI R1, #0 \ \ So R1 is now between 0 and 3, and can be \ added to the colour numbers below to add \ the correct level of brightness MOV R8, #%00001111 \ Set R0 = bits 8-11 of the colour in R7, so AND R0, R8, R7, LSR #8 \ if the face colour is &rgb, this is &r AND R2, R8, R7, LSR #4 \ Set R2 = bits 4-7 of the colour in R7, so \ if the face colour is &rgb, this is &g AND R7, R7, R8 \ Set R7 = bits 0-3 of the colour in R7, so \ if the face colour is &rgb, this is &b ADD R0, R0, R1 \ Set R0 = R0 + R1 and clip to a maximum CMP R0, #16 \ value of 15, so this adds the face MOVHS R0, #15 \ brightness to the red channel and ensures \ the result fits into four bits ADD R2, R2, R1 \ Set R2 = R2 + R1 and clip to a maximum CMP R2, #16 \ value of %00001111, so this adds the face MOVHS R2, #15 \ brightness to the green channel and \ ensures the result fits into four bits ADD R7, R7, R1 \ Set R7 = R7 + R1 and clip to a maximum CMP R7, #16 \ value of %00001111, so this adds the face MOVHS R7, #15 \ brightness to the blue channel and ensures \ the result fits into four bits \ We now build a VIDC colour number in R8 \ by combining the three channels into one \ byte, which we then replicate four times \ to get a 32-bit colour number \ \ The byte is of the form: \ \ * Bit 7 = blue bit 3 \ * Bit 6 = green bit 3 \ * Bit 5 = green bit 2 \ * Bit 4 = red bit 3 \ * Bit 3 = blue bit 2 \ * Bit 2 = red bit 2 \ * Bit 1 = sum of red/green/blue bit 1 \ * Bit 0 = sum of red/green/blue bit 0 \ \ We now build this colour number in R8 from \ the red, green and blue values in R0, R2 \ and R7 ORR R8, R2, R7 \ Set R8 to the bottom three bits of: AND R8, R8, #%00000011 \ ORR R8, R8, R0 \ (the bottom two bits of R2 OR R7) OR R0 AND R8, R8, #%00000111 \ \ So this sets bits 0, 1 and 2 of R8 as \ required TST R0, #%00001000 \ If bit 3 of the red channel in R0 is set, ORRNE R8, R8, #%00010000 \ set bit 4 of R8 AND R2, R2, #%00001100 \ Clear all bits of the green channel in R2 \ except bits 2-3 ORR R8, R8, R2, LSL #3 \ And stick them into bits 5-6 of R8 TST R7, #%00000100 \ If bit 2 of the blue channel in R7 is set, ORRNE R8, R8, #%00001000 \ set bit 3 of R8 TST R7, #%00001000 \ If bit 3 of the blue channel in R7 is set, ORRNE R8, R8, #%10000000 \ set bit 7 of R8 ORR R8, R8, R8, LSL #8 \ Duplicate the lower byte of R8 into the ORR R8, R8, R8, LSL #16 \ other three bytes in the word to produce ORR R8, R8, R8, LSL #24 \ a four-pixel colour word containing four \ pixels of this colour \ Finally we can draw the face, using the \ colour in R8 ADD R4, R10, R4, LSL #4 \ Set (R0, R1) to the two words at offset LDMIA R4, {R0-R1} \ R4 * 16 from the table at R10, which is \ the pixel coordinate of the vertex number \ in R4, i.e. the first vertex in this face \ \ We multiply the vertex number by 16 as \ there are four words per vertex in \ vertexProjected, which is 16 bytes per \ face ADD R5, R10, R5, LSL #4 \ Set (R2, R3) to the two words at offset LDMIA R5, {R2-R3} \ R5 * 16 from the table at R10, which is \ the pixel coordinate of the vertex number \ in R5, i.e. the second vertex in this face ADD R6, R10, R6, LSL #4 \ Set (R4, R5) to the two words at offset LDMIA R6, {R4-R5} \ R6 * 16 from the table at R10, which is \ the pixel coordinate of the vertex number \ in R6, i.e. the third vertex in this face BL DrawTriangleToBuffer \ Draw the triangle for this face using the \ projected vertices for the face, drawn in \ the colour in R8, and draw it one buffer \ nearer the camera than the shadow, so the \ shadow never overlaps the object .dobj5 LDMFD R13!, {R8-R9, R11-R12} \ Retrieve the registers that we stored on \ the stack before processing the face ADD R9, R9, #16 \ Add 16 to R9 so it points to the next \ batch of face data (R9 already points to \ the fourth word in the current face data, \ so this skips the next four, thereby \ skipping all seven words of face data) SUBS R8, R8, #1 \ Decrement the loop counter, which keeps \ track of the number of faces we have \ processed BNE dobj3 \ Loop back to dobj3 to move on to the next \ face, until we have processed them all LDMFD R13!, {R6-R12, PC} \ Retrieve the registers that we stored on \ the stack and return from the subroutine