Skip to navigation


Landscape: DrawLandscapeAndBuffers (Part 1 of 4)

Name: DrawLandscapeAndBuffers (Part 1 of 4) [Show more] Type: Subroutine Category: Landscape Summary: Draw the landscape and the contents of the graphics buffers, from the back of the screen to the front Deep dive: Drawing the landscape Depth-sorting with the graphics buffers
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * LoseLife calls DrawLandscapeAndBuffers * MainLoop calls DrawLandscapeAndBuffers

Both the landscape and objects are drawn one tile row at a time, working from the back to the front. In each iteration, we process a horizontal row of tile corners, working from left to right and back to front. For each corner we draw a landscape tile where possible (i.e. when we have already processed the other three corners in that tile, so we don't start drawing until we reach the second corner on the second row). Objects are drawn after the tiles on which they sit. This is achieved by staggering the drawing of objects so they are drawn two rows later than the landscape, so we draw an object two iterations after we have finished drawing all four of its surrounding tiles. This ensures that the landscape always appears behind the objects that sit on it. More specifically, we do the following: * Part 1: Start by setting up all the variables * We now step through each row of tile corners, working through the tile corners from left to right, one row at a time, keeping track of the row number in tileCornerRow = 0 to 10 For each row of tile corners, we do the following: * Part 2: Work along the current row of tile corners, from left to right, one corner coordinate at a time, and draw each tile as a quadrilateral once we have four valid corner coordinates from the previous row and previous column * Part 3: If tileCornerRow >= 2, also draw the contents of the graphics buffer with number tileCornerRow - 2 * Part 4: Finish by drawing the objects in graphics buffer 9 and graphics buffer 10 So we draw the objects in graphics buffer 0 just after we process tile corner row 2, so that's just after we draw the tiles between corner rows 1 and 2. Note that the game allocates memory to an extra graphics buffer, but only buffers numbers 0 to TILE_Z are used.
.DrawLandscapeAndBuffers STMFD R13!, {R5-R9, R14} \ Store the registers that we want to use on \ the stack so they can be preserved LDR R3, [R11, #zCamera] \ Set R3 to the z-coordinate of the camera, \ which is the 3D coordinate in the game \ world at the middle-back of the on-screen \ view AND R9, R3, #&FF000000 \ Set R9 to the z-coordinate of the tile \ containing the camera, as this rounds the \ coordinate down to the nearest tile SUB R3, R3, R9 \ Set R3 = R3 - R9 \ = zCamera - tile containing zCamera \ \ So R3 contains the fractional element of \ zCamera in terms of whole tiles STR R9, [R11, #zCameraTile] \ Set zCameraTile to the z-coordinate of the \ tile containing the camera (though this \ isn't actually used - the value of R9 is \ used below, though) LDR R4, [R11, #xCamera] \ Set R4 to the x-coordinate of the camera, \ which is the 3D coordinate in the game \ world at the middle-back of the on-screen \ view AND R8, R4, #&FF000000 \ Set R8 to the x-coordinate of the tile \ containing the camera, as this rounds the \ coordinate down to the nearest tile SUB R4, R4, R8 \ Set R4 = R4 - R8 \ = xCamera - tile containing xCamera \ \ So R4 contains the fractional element of \ xCamera in terms of whole tiles STR R8, [R11, #xCameraTile] \ Set xCameraTile to the x-coordinate of the \ tile containing the camera ADD R5, R11, #xLandscapeRow \ Set R5 to the address of xLandscapeRow LDR R0, landscapeOffsetAddr \ Fetch the landscape offset vector into LDMFD R0, {R0-R2} \ (R0, R1, R2), which defines the offset \ that we apply to the on-screen landscape \ to move it away from the viewer so it \ fits nicely on-screen SUB R0, R0, R4 \ Subtract the fractional element of xCamera \ from the landscape offset x-coordinate in \ R0 SUB R2, R2, R3 \ Subtract the fractional element of zCamera \ from the landscape offset z-coordinate in \ R2 STMIA R5, {R0-R2} \ (R0, R1, R2) now contains the coordinate \ of the far-left corner of the back row of \ the landscape, which is the first corner \ row that we will process, so store it in \ (xLandscapeRow, yLandscapeRow, \ zLandscapeRow) MOV R0, #0 \ Set tileCornerRow = 0 to use as the STRB R0, [R11, #tileCornerRow] \ number of the tile corner row we are \ currently processing, working through the \ corner rows from row 0 (at the back) to \ row 10 (at the front) MOV R6, #0 \ Set R6 = 0 to use as the address of the \ previous row's coordinates, which we set \ to zero as we don't have a previous row \ yet ADD R7, R11, #cornerStore1 \ Set R7 to the address of cornerStore1 STRB R6, [R11, #tileRowOddEven] \ Set tileRowOddEven = 0, which we will flip \ between 0 and 1 for each tile corner row \ that we process \ So we now have the following variables set \ up, ready for the iteration through each \ row of tile corners, stepping from left to \ right, column by column: \ \ * R6 = 0 \ \ R6 always points to the set of corner \ pixel coordinates from the previous \ tile corner row, so it starts out as \ zero as there is no previous row at \ this point \ \ * R7 = address of cornerStore1 \ \ R7 always points to the place where we \ store the pixel coordinates for the \ current row corner as we work our way \ along the row it (we store these \ coordinates so we can draw the tiles \ when we're on the next corner row in \ the next iteration) \ \ * R9 = the z-coordinate of the tile \ containing the camera \ \ So (x, R9) is the coordinate of each \ corner on the corner row we're working \ along, starting from the far-left \ corner (as the camera position is \ actually at the back of the on-screen \ landscape) \ \ * zLandscapeRow = the z-coordinate of \ the back corner row of the landscape \ \ So zLandscapeRow keeps track of the \ z-coordinate of the tile corner row \ that we are processing, decreasing as \ we move towards the front of the tile \ landscape \ \ * tileRowOddEven = 0 \ \ tileRowOddEven flips between 0 and 1 \ for each tile corner row, so we can \ set the correct values of R6 and R7 at \ the end of each iteration \ \ * tileCornerRow = 0 \ \ tileCornerRow contains the number of \ the tile corner row that we are \ currently processing, which increments \ on each iteration as we move forwards \ \ * xCameraTile is the x-coordinate of the \ tile containing the camera \ \ This is the same as the x-coordinate of \ the middle of each tile corner row, \ rounded down to the nearest tile \ \ We now fall through into part 2