\ We're now ready to iterate through the \ landscape, from left to right and back to \ front, looping back to land1 after \ processing each corner row .land1 LDRB R1, [R11, #tileCornerRow] \ Set R1 to the number of the tile corner \ row we are currently processing LDR R0, landscapeConfigAddr \ Set R0 to the address of the pair of ADD R0, R0, R1, LSL #1 \ bytes in the landscapeConfig table for the \ tile row number in R1 LDRB R10, [R0, #1] \ Set R10 to the second byte from the pair \ in landscapeConfig, which is the number \ of tile corners in the row \ \ We now use R10 as a loop counter when \ working our way along the row, counting \ tile corners as we progress LDRB R0, [R0] \ Set unusedConfig to the first byte from STRB R0, [R11, #unusedConfig] \ the pair in landscapeConfig, though this \ value is not used, so this has no effect ADD R0, R11, #xLandscapeRow \ Fetch the coordinate from (xLandscapeRow, LDMIA R0, {R0-R2} \ yLandscapeRow, zLandscapeRow) into \ (R0, R1, R2), so they contain the \ coordinates of the left end of the corner \ row that we need to process ADD R4, R11, #xLandscapeCol \ Store the coordinates in (xLandscapeCol, STMIA R4, {R0-R2} \ yLandscapeCol, zLandscapeCol) so we can \ start processing from the left end of this \ tile corner row, using these coordinates \ as we work through the columns, updating \ yLandscapeCol with the landscape height as \ we go LDR R8, [R11, #xCameraTile] \ Set R8 = xCameraTile - LANDSCAPE_X, so SUB R8, R8, #LANDSCAPE_X \ R8 is now the coordinate of the tile \ corner at the left end of the corner row, \ as subtracting the offset of the landscape \ effectively moves the camera to the left \ by that amount MOV R0, #&80000000 \ Set previousColumn = &80000000 to denote STR R0, [R11, #previousColumn] \ that we don't have corner coordinates from \ the previous column yet (as we are \ starting a new row) \ We now do the following loop R10 times, \ once for each of the tile corners in the \ row, looping back to land2 as we move \ right through the columns .land2 BL GetLandscapeAltitude \ Set R0 to the altitude of the landscape at \ coordinates (x, z) = (R8, R9), which is \ the current corner on this row LDR R14, [R11, #yCamera] \ Set yLandscapeCol = R0 - yCamera SUB R0, R0, R14 \ = altitude - yCamera STR R0, [R11, #yLandscapeCol] \ \ So this stores the y-coordinate of the \ landscape at this point, as we're seeing \ it from the point of view of the camera \ (so this will move it down the screen if \ the player is flying high, for example) ADD R0, R11, #xLandscapeCol \ Set R0 to the address of xLandscapeCol BL ProjectVertexOntoScreen \ Project (xLandscapeCol, yLandscapeCol, \ zLandscapeCol) onto the screen, returning \ the results in (R0, R1), so this projects \ the tile corner as it sits on the \ landscape \ \ This also sets the C flag if the vertex is \ too far away to draw BCS land4 \ If the vertex is too far away to draw then \ jump to land4 to skip the following STMIA R7!, {R0-R1} \ Store the corner coordinates in (R0, R1) \ in R7, updating R7 as we go, as R7 is \ where we store the tile corner pixel \ coordinates as we go (so this stores the \ corner coordinates in either cornerStore1 \ or cornerStore2, so we can fetch them when \ we process the next tile corner row) CMP R6, #0 \ If R6 = 0 then this is either the very BEQ land4 \ first tile corner row, or we have already \ fetched all the data for the previous row \ from the storage at R6 \ \ In either case, jump to land4 to skip \ drawing this tile as we can't draw tiles \ without the corresponding corner \ coordinates from the previous row and \ previous column LDMIA R6!, {R2-R3} \ Load the corner pixel coordinates from R6 \ into (R2, R3), updating R6 as we go, so \ this fetches the corresponding corner \ pixel coordinates from the previous tile \ corner row (i.e. from the opposite corner \ store to the one where we just stored this \ row's coordinate) CMP R2, #&80000000 \ If R2 = &80000000 then we have reached the MOVEQ R6, #0 \ end of the storage in R6, so set R6 = 0 BEQ land4 \ to prevent any more access attempts from \ the storage in R6, and jump to land4 to \ skip drawing this tile \ If we get here then we have the \ following pixel corner coordinates \ calculated: \ \ (R0, R1) = new corner from this row \ \ (R2, R3) = corresponding corner from \ previous row (i.e. the corner \ that's back by one row) STMFD R13!, {R6-R8} \ Store the registers that we want to use on \ the stack so they can be preserved ADD R14, R11, #previousColumn \ We now need to fetch the previous corners, LDMIA R14, {R4-R7} \ looking left along the tile row to the \ previous column of corners, so we can draw \ a tile from there to the new corner \ \ We will have stored these previous corners \ in the previousColumn table in the \ previous iteration, so fetch them into \ R4 to R7 like this: \ \ (R4, R5) = corner from the column to the \ left on this row \ \ (R6, R7) = corresponding corner from the \ previous row STMIA R14, {R0-R3} \ Store the new corners from this corner row \ in (R0, R1) and (R2, R3) in previousColumn \ so we can fetch them in the next iteration \ in the same way CMP R4, #&80000000 \ If R4 = &80000000 then this is actually BEQ land3 \ the first column of corner coordinates in \ this row, so we can't yet draw the tile, \ so jump to land3 to skip the drawing part \ If we get here then we actually have a \ tile to draw BL GetLandscapeTileColour \ Calculate the tile colour, depending on \ the slope, and return it in R8 BL DrawQuadrilateral \ Draw the tile by drawing a quadrilateral \ in colour R8 with corners at: \ \ (R0, R1) = the corner we're processing \ (R2, R3) = same corner in previous row \ (R4, R5) = previous column in this row \ (R6, R7) = previous row, previous column \ \ So this draws the tile we want on-screen .land3 LDMFD R13!, {R6-R8} \ Retrieve the registers that we stored on \ the stack .land4 SUBS R10, R10, #1 \ Decrement the loop counter in R10, which \ counts the number of tile corners in this \ row LDRNE R0, [R11, #xLandscapeCol] \ If we haven't yet processed all the tile ADDNE R0, R0, #TILE_SIZE \ corners in this row, add a tile's width to STRNE R0, [R11, #xLandscapeCol] \ xLandscapeCol and R8 to move them along ADDNE R8, R8, #TILE_SIZE \ the row to the next tile corner, and jump BNE land2 \ back to land2 to process the next corner \ By this point have drawn all the tiles in \ this row, so we now move on to the objects \ in the graphics buffersName: DrawLandscapeAndBuffers (Part 2 of 4) [Show more] Type: Subroutine Category: Landscape Summary: Draw a row of landscape tiles Deep dive: Drawing the landscape Depth-sorting with the graphics buffersContext: See this subroutine in context in the source code References: No direct references to this subroutine in this source file

[X]

Subroutine DrawQuadrilateral (category: Drawing triangles)

Draw a quadrilateral (i.e. two triangles)

[X]

Subroutine GetLandscapeAltitude (category: Landscape)

Calculate the altitude of the landscape for a given coordinate

[X]

Subroutine GetLandscapeTileColour (category: Landscape)

Calculate the colour of the landscape tile currently being drawn

[X]

Configuration variable LANDSCAPE_X = LANDSCAPE_X_WIDTH / 2

The x-coordinate of the landscape offset, which is set to the whole number of tiles that fit into the half the width of the landscape, so we end up looking at the middle point of the landscape

[X]

Subroutine ProjectVertexOntoScreen (category: Maths (Geometry))

Project a vertex coordinate from a 3D object onto the screen

[X]

Configuration variable TILE_SIZE = &01000000

The length of one side of a square landscape tile in 3D coordinates

[X]

Label land2 is local to this routine

[X]

Label land3 is local to this routine

[X]

Label land4 is local to this routine

[X]

Variable landscapeConfigAddr (category: Landscape)

The address of the landscapeConfig table

[X]

Configuration variable previousColumn = &C4

The corner coordinates of the previous column while working along a row from left to right

[X]

Configuration variable tileCornerRow = &E4

The number of the landscape tile corner row that is currently being processed

[X]

Configuration variable unusedConfig = &F0

Storage for the first configuration value in the landscapeConfig table, which is stored but not used

[X]

Configuration variable xCameraTile = &148

The 3D x-coordinate of the camera, clipped to the nearest tile

[X]

Configuration variable xLandscapeCol = &170

The x-coordinate of the far-left corner of the column (i.e. tile) that we are drawing in the current landscape row, where columns run in and out of the screen (this is a relative coordinate)

[X]

Configuration variable xLandscapeRow = &160

The x-coordinate of the far-left corner of the landscape row that we are drawing, where rows run from left to right across the screen (this is a relative coordinate)

[X]

Configuration variable yCamera = &140

The 3D y-coordinate of the camera position (though note that the camera position is actually at the back of the on-screen landscape, not the front)

[X]

Configuration variable yLandscapeCol = &174

The y-coordinate of the far-left corner of the column (i.e. tile) that we are drawing in the current landscape row, where columns run in and out of the screen (this is a relative coordinate)