Skip to navigation

Revs on the BBC Micro

Dashboard: DrawDashboardLine

Name: DrawDashboardLine [Show more] Type: Subroutine Category: Dashboard Summary: Draw a hand on the rev counter or a line on the steering wheel
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * UpdateDashboard calls DrawDashboardLine

This routine is a mode 5 Bresenham line-drawing routine, which modifies itself to cater for lines of different slopes.
Arguments: V The slope of the line to draw, which is expressed as a quadrant number, where quadrant 0 is from 12 o'clock to 3 o'clock, with quadrants ordered 0 to 3 in a clockwise order: * 0 = %000 = Quadrant 0, first half (12:00 to 1:30) Steep slope, right and up Step up along y-axis (stepAxis = DEY) Move right along x-axis (shortAxis = INX) * 1 = %001 = Quadrant 0, second half (1:30 to 3:00) Shallow slope, right and up Step right along x-axis (stepAxis = INX) Move up along y-axis (shortAxis = DEY) * 2 = %010 = Quadrant 1, first half (3:00 to 4:30) Shallow slope, right and down Step right along x-axis (stepAxis = INX) Move down along y-axis (shortAxis = INY) * 3 = %011 = Quadrant 1, second half (4:30 to 6:00) Steep slope, right and down Step down along y-axis (stepAxis = INY) Move right along x-axis (shortAxis = INX) * 4 = %100 = Quadrant 2, first half (6:00 to 7:30) Steep slope, left and down Step down along y-axis (stepAxis = INY) Move left along x-axis (shortAxis = DEX) * 5 = %101 = Quadrant 2, second half (7:30 to 9:00) Shallow slope, left and down Step left along x-axis (stepAxis = DEX) Move down along y-axis (shortAxis = INY) * 6 = %110 = Quadrant 3, first half (9:00 to 10:30) Shallow slope, left and up Step left along x-axis (stepAxis = DEX) Move up along y-axis (shortAxis = DEY) * 7 = %111 = Quadrant 3, second half (10:30 to 12:00) Steep slope, left and up Step up along y-axis (stepAxis = DEY) Move left along x-axis (shortAxis = DEX) (Q P) The screen address of the character block containing the line's starting point Y The pixel row within the character block containing the line's starting point (0 to 7) U The number of pixels to step along the step axis: * The number of pixels along the longer (step) axis when drawing the rev counter * 6 when drawing the steering wheel line T The slope error for each step along the step axis is T/SS, and T is set to: * The distance between the hand and quadrant when drawing the rev counter hand * When drawing the steering wheel line: 0-37 when the line is close to the centre (in the top two quadrants either side of the centre) 37-16 when line is further from the centre (in the left and right quadrants) SS The slope error for each step along the step axis is T/SS, and SS is set to: * The same as U when drawing the rev counter hand i.e. the number of pixels along the longer (step) axis * A value from wheelPixels when drawing the steering wheel line (38 to 53) H The starting index to use in the pixelByte and yLookupLo+8 lookup tables: * %000 when drawing the rev counter hand, so the line gets drawn in white * %100 when drawing the steering wheel line, so the line gets drawn in black W The pixel number (0-7) of the first pixel to draw along the x-axis
.DrawDashboardLine LDX V \ Modify the instruction at dlin2 to the V-th shortAxis LDA shortAxis,X \ instruction STA dlin2 LDA stepAxis,X \ Modify the instruction at dlin8 to the V-th stepAxis STA dlin8 \ instruction \ The following code has the instructions for V = %010, \ which has INY at dlin2 for the short axis, and INX at \ dlin8 for the step axis, so that's this kind of line: \ \ * Quadrant 1, first half (3:00 to 4:30) \ * Shallow slope, right and down \ * Step right along x-axis (stepAxis = INX) \ * Move down along y-axis (shortAxis = INY) LDX W \ Set X = W, so X contains the position of the current \ pixel within the pixel row, if there were eight pixels \ per row LDA #0 \ Set A = -SS SEC \ SBC SS \ So this is the starting point for our slope error \ calculation CLC \ Clear the C flag for the following addition .dlin1 \ We use A to keep track of the slope error, adding the \ step along the smaller axis (in T) until it reaches 0, \ at which point it is a multiple of SS and we need \ to move one pixel along the smaller axis ADC T \ Set A = A + T \ \ So A is updated with the slope error BCC dlin3 \ If the addition didn't overflow, then the result in A \ is still negative, so skip the following instruction \ The slope error just overflowed (in other words, the \ cumulative slope error in A just reached a multiple of \ SS), so we need to adjust the slope error to make \ it negative again, and we need to step along the \ shorter axis SBC SS \ Subtract SS from the cumulative slope error to \ bring it back to being negative, so we can detect when \ it reaches next multiple of SS .dlin2 INY \ Increment Y to move down along the y-axis (i.e. along \ the shorter axis) \ \ This instruction is modified at the start of this \ routine, depending on the slope of the line in V .dlin3 STA II \ Store the updated slope error in II, so we can \ retrieve it below, ready for the next iteration of the \ drawing loop TXA \ X contains the position of the current pixel within LSR A \ the pixel row, in the range 0 to 7, so set A to half AND #%00000011 \ this value to get the mode 5 pixel number (as there \ are only four pixels per pixel byte on mode 5) ORA H \ Set bit 2 of A if this is the steering wheel, which \ is the same as adding 4 STA V \ Store the result in V, so V contains the pixel number \ (0 to 3) of the pixel to draw, plus 4 if this is the \ steering wheel (4 to 7) TXA \ X contains the position of the current pixel within \ the pixel line, so put this in A BPL dlin4 \ If bit 7 of A is clear, jump to dlin4 \ Otherwise we need to move (Q P) to the previous \ character block to the left, by subtracting 8 (as \ there are 8 bytes per character block) LDX #7 \ Set X = 7 to set as the new value of W below LDA P \ Set (Q P) = (Q P) - 8 SEC \ SBC #8 \ starting with the low bytes STA P BCS dlin5 \ And then the high bytes DEC Q BCS dlin5 \ This instruction has no effect, as we already passed \ through the BCS above, which is presumably a bug (this \ should perhaps be a BCC?) .dlin4 CMP #8 \ If A < 8, jump to dlin5 BCC dlin5 \ Otherwise we need to move (Q P) to the next character \ block to the right, by adding 8 (as there are 8 bytes \ per character block) LDX #0 \ Set X = 0 to set as the new value of W below LDA P \ Set (Q P) = (Q P) + 8 CLC \ ADC #8 \ starting with the low bytes STA P BCC dlin5 \ And then the high bytes INC Q .dlin5 STX W \ Store X in W, so W moves along one pixel to the right LDX lineBufferSize \ Set X to the size of the line buffer, which gives us \ the index of the next empty space in the buffer TYA \ Y contains the number of the pixel row within the \ current character block, so put this in A BPL dlin6 \ If A >=0, jump to dlin6 \ Otherwise we need to move (Q P) to the next character \ row above, by subtracting &140 (as there are &140 \ bytes per character row) LDA P \ Set (Q P) = (Q P) - &140 SEC \ SBC #&40 \ starting with the low bytes STA P LDA Q \ And then the high bytes SBC #&01 STA Q LDY #7 \ Set Y = A = 7 as the new value of Y TYA BNE dlin7 \ Jump to dlin7 (this BNE is effectively a JMP as A is \ never zero) .dlin6 CMP #8 \ If A < 8, jump to dlin7 BCC dlin7 \ Otherwise we need to move (Q P) to the next character \ row below, by adding &140 (as there are &140 bytes per \ character row) LDA P \ Set (Q P) = (Q P) + &140 CLC \ ADC #&40 \ starting with the low bytes STA P LDA Q \ And then the high bytes ADC #&01 STA Q LDY #0 \ Set Y = A = 0 as the new value of Y TYA .dlin7 \ We now store the details of the pixel we are about \ to overwrite in the line buffer, which stores a screen \ address plus the original contents of that address \ \ We get the screen address by adding the address of the \ character block in P to the number of the pixel row \ within the character in A, which we can do with an ORA \ as P only occupies bits 3 to 7, while A only occupies \ bits 0 to 2 ORA P \ Store the address we are about to overwrite in the STA lineBufferAddrLo,X \ next empty space at the end of the line buffer, i.e. \ the X-th byte of (lineBufferAddrHi lineBufferAddrLo), \ starting with the low byte of the address LDA Q \ And then the high byte of the address STA lineBufferAddrHi,X LDA (P),Y \ Store the current pixel contents into the pixel STA lineBufferPixel,X \ contents buffer at lineBufferPixel INC lineBufferSize \ Increment the size of the pixel buffers, as we just \ added an entry LDX V \ Set X = V, so X now contains the pixel number \ (0 to 3) of the pixel to draw, plus 4 if this is the \ steering wheel (4 to 7) AND yLookupLo+8,X \ Apply the X-th pixel mask from yLookupLo+8, so this \ clears the X-th pixel in the pixel row (the table \ contains the same bytes in 0 to 3 as in 0 to 7) ORA pixelByte,X \ OR with a pixel byte with pixel X set, so this sets \ the X-th pixel to colour 2 (white) if X is 0 to 3, or \ colour 0 (black) if X is 4 to 7 - so the rev counter \ hand is white, while the steering wheel line is black STA (P),Y \ Draw the pixel byte to the screen \ We now set up all the variables so we can loop back \ to dlin1 for the next pixel LDX W \ Set X = W LDA II \ Set A to the current slope error, which we stored in \ II above CLC \ Clear the C flag for the addition at the start of the \ loop .dlin8 INX \ Increment X to step right along the x-axis (i.e. along \ the longer axis) \ \ This instruction is modified at the start of this \ routine, depending on the slope of the line in V DEC U \ Decrement the pixel counter BMI dlin9 \ If we have drawn the correct number of pixels along \ the longer axis, jump to dlin9 to return from the \ subroutine as we have finished drawing the line JMP dlin1 \ Otherwise loop back to draw the next pixel .dlin9 RTS \ Return from the subroutine