Skip to navigation

Lander on the Acorn Archimedes

Landscape: GetLandscapeTileColour

Name: GetLandscapeTileColour [Show more] Type: Subroutine Category: Landscape Summary: Calculate the colour of the landscape tile currently being drawn Deep dive: Drawing the landscape Screen memory in the Archimedes
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * DrawLandscapeAndBuffers (Part 2 of 4) calls GetLandscapeTileColour

Returns: R8 The colour of the landscape tile
.GetLandscapeTileColour STMFD R13!, {R0-R4, R14} \ Store the registers that we want to use on \ the stack so they can be preserved LDR R3, [R11, #prevAltitude] \ Set R3 to the altitude of the previous \ point on the landscape LDR R4, [R11, #altitude] \ Set R4 to the altitude of the current \ point on the landscape SUBS R14, R3, R4 \ Set R14 to the slope of the tile, which we MOVMI R14, #0 \ get from the change of altitude from the \ previous point to this one, making sure \ the slope value is greater than zero: \ \ R14 = min(0, prevAltitude - altitude) \ \ The y-axis that measures altitude goes \ down the screen (counterintuitively), so \ if prevAltitude has a bigger value than \ altitude, this means the previous point \ is lower down than the current point \ \ As we draw the landscape from left to \ right, this means the slope value will be \ non-zero for tiles that face left, with a \ greater value for steeper slopes, while \ tiles that face right will have a slope \ value of zero \ We now calculate the colour, with the red, \ green and blue channels in R0, R1 and R2 \ respectively AND R2, R4, #&10 \ This instruction appears to have no \ effect, as we overwrite the result in the \ next instruction, but it looks like it's \ all that remains of an experiment to add \ blue to the landscape MOV R2, #0 \ Set the blue channel in R2 to zero, as we \ only use blue for the sea \ We now set the green and red channels \ depending on bits 2 and 3 of the altitude, \ for red and green respectively \ \ This makes the green channel change more \ slowly between neighbouring tiles, with \ the red channel changing more quickly, \ giving the overall effect of a gentle \ green landscape pockmarked with small \ groups of red-brown dirt AND R1, R4, #%00001000 \ Set the green channel in R1 to bit 3 of MOV R1, R1, LSR #1 \ the current point's altitude, as follows: ADD R1, R1, #4 \ \ R1 = (bit 3) * 4 + 4 \ \ So it's 4 if bit 3 is clear, or 8 if bit 3 \ is set AND R0, R4, #%00000100 \ Set the red channel in R0 to bit 2 of the \ current point's altitude CMP R4, #LAUNCHPAD_ALTITUDE \ If the current point is on the launchpad, MOVEQ R0, #4 \ set the colour to grey, i.e. red, green MOVEQ R1, #4 \ and blue all have the same value of 4 MOVEQ R2, #4 CMP R4, #SEA_LEVEL \ If both the previous and current points CMPEQ R3, #SEA_LEVEL \ are at sea level, set the colour to blue, MOVEQ R1, #0 \ i.e. the blue channel has value 4 while MOVEQ R2, #4 \ red and green are zero MOVEQ R0, #0 LDRB R8, [R11, #tileCornerRow] \ Set R8 to the number of the tile corner \ row that we're processing, so it goes from \ 1 at the back to TILES_Z - 1 at the front, \ or 1 to 10 (it doesn't start at zero as we \ don't draw any tiles for the very first \ row of tile corners, so we don't call this \ routine) ADD R3, R8, R14, LSR #22 \ Set the tile's brightness in R3 to: \ \ tileCornerRow + slope >> 22 \ \ where tileCornerRow is 1 at the back and \ TILES_Z - 1 at the front \ \ As we draw the landscape from back to \ front and left to right, this means that: \ \ * Tiles nearer the front will have a \ higher brightness level than those at \ the back (as tileCornerRow will be \ higher for closer tiles) \ \ * Tiles that face to the left will have \ a higher brightness level than those \ that face to the right, with steeper \ sloping tiles being brighter than \ shallow ones (as slope will be higher \ for steeper sloping tiles) \ \ * Tiles that face to the right will have \ fixed brightness levels that only vary \ with distance and not with slope (as \ slope is zero for tiles that face \ right) \ \ This implements a light source that is \ directly above and slightly to the left ADD R0, R0, R3 \ Add the brightness in R3 to all three ADD R1, R1, R3 \ channels ADD R2, R2, R3 CMP R0, #16 \ Ensure that the red channel in R0 fits MOVHS R0, #15 \ into four bits CMP R1, #16 \ Ensure that the green channel in R1 fits MOVHS R1, #15 \ into four bits CMP R2, #16 \ Ensure that the blue channel in R2 fits MOVHS R2, #15 \ 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, R1 \ and R2 ORR R8, R1, R2 \ Set R8 to the bottom three bits of: AND R8, R8, #%00000011 \ ORR R8, R8, R0 \ (the bottom two bits of R1 OR R2) 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 R1, R1, #%00001100 \ Clear all bits of the green channel in R1 \ except bits 2-3 ORR R8, R8, R1, LSL #3 \ And stick them into bits 5-6 of R8 TST R2, #%00000100 \ If bit 2 of the blue channel in R2 is set, ORRNE R8, R8, #%00001000 \ set bit 3 of R8 TST R2, #%00001000 \ If bit 3 of the blue channel in R2 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 LDMFD R13!, {R0-R4, PC} \ Retrieve the registers that we stored on \ the stack and return from the subroutine