Skip to navigation

Revs on the BBC Micro

Drawing objects: DrawObjectEdge (Part 1 of 5)

Name: DrawObjectEdge (Part 1 of 5) [Show more] Type: Subroutine Category: Drawing objects Summary: Draw the specified edge of an object part Deep dive: Creating objects from edges
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * DrawObjectEdges calls DrawObjectEdge * ProcessContact calls via DrawObjectEdge-1

This part of the routine calculates the pixel x-coordinate of the edge, plus the block number and pixel x-coordinate of the next edge (if there is one), so we can use them in the next call to DrawObjectEdge.
Arguments: topTrackLine Top track line of the edge (higher value, 0 to 79) bottomTrackLine Bottom track line of the edge (lower value, 0 to 79) thisEdge This edge (as a scaled scaffold measurement) nextEdge The next edge (as a scaled scaffold measurement) xPixelCoord The pixel x-coordinate of the centre of the object colourData Colour data: * Bits 0-1 = logical fill colour * Bits 2-3 = logical edge colour * Bit 4 = if set and this is a left or right edge, then use the fill colour instead of the edge colour if this is an outside edge (i.e. a left edge in the left half of the screen, or a right edge in the right half of the screen), so the edge is effectively hidden A The fill colour to the right of the edge to draw: * For left edges: bits 0-1 contain the fill colour from bits 0-1 of the colour data * For right edges: contains 0 * For extra edges: bits 0-1 contain the fill colour from bits 0-1 of the colour data Y Edge type: * 0 = second or third edge in a four-edge object part (an "extra edge") * 1 = left edge * 2 = right edge rightOfEdge The fill byte to the right of the previous edge (or, if this is the first edge, the background colour to the left of the first edge) If this is a second call to DrawObjectEdge and we need to draw this edge in the same pixel byte as the previous edge, this contains the pixel byte from the previous call with the first edge already drawn blockNumber For extra or right edges only: the dash data block number of the previous edge drawn by DrawObjectEdge nextEdgeCoord For extra or right edges only: the pixel x-coordinate of the edge to draw (as returned by the previous call to DrawObjectEdge) nextBlockNumber For extra or right edges only: the data block number of the edge to draw (returned by the previous call to DrawObjectEdge) prevEdgeInByte Determines whether we have already inserted the previous edge into the pixel byte we are building * 0 = there is no other edge in the pixel byte we are building * Non-zero = the previous edge is already in the pixel byte we are building, and the current edge needs to go in the same byte edgePixelMask For extra or right edges only: * 0 = there is no other edge in the pixel byte we are building * Non-zero = the pixel mask of the edge that was drawn into rightOfEdge in the previous call
Returns: blockNumber The dash data block number that was drawn into rightOfEdge The fill byte to the right of the edge we just drew: * If we just successfully drew an edge and drew the result on-screen, this contains the fill colour of the object * If we created a pixel byte but the next edge needs to be drawn in the same byte, this contains the pixel byte from this call edgePixelMask The pixel mask of the edge that was drawn, which will: * Be empty if the previous edge was already drawn and we do not need to share this pixel byte with the previous edge * Contain set pixels for the previous edge if both this edge and the previous edge need to share the same pixel byte nextEdgeCoord The pixel x-coordinate for the next edge nextBlockNumber The dash data block number for the next edge prevEdgeInByte The correct setting for the next edge: * 0 if the next edge is not in the same byte as the one we just drew * Non-zero (bit 7 is set) if the next edge is in the same byte as the one we just drew (in which case the screen has not been updated, and the next call to DrawObjectEdge needs to insert the next edge into the pixel byte in rightOfEdge, using the pixel mask in edgePixelMask)
Other entry points: DrawObjectEdge-1 Contains an RTS
.DrawObjectEdge STY J \ Set J to the edge type in Y, so we can fetch it later LDX rightOfEdge \ Set leftOfEdge = rightOfEdge, so we effectively step STX leftOfEdge \ along the line, from the previous edge to this edge \ (so the fill byte to the right of the previous edge \ becomes the fill byte to the left of this edge) AND #3 \ Set X to bits 0-1 of A, which contains the logical TAX \ colour of the object's fill colour LDA objectPalette,X \ Set rightOfEdge to logical colour X from the object STA rightOfEdge \ palette, so we fill the object to the right of this \ edge with the colour in A LDA blockNumber \ Set prevBlockNumber to the dash data block number that STA prevBlockNumber \ was left over from the previous call to DrawObjectEdge \ so we can use it if this isn't a left edge LDA colourData \ Set X to bits 2-3 of colourData, which contains the AND #%00001100 \ logical colour of the edge we want to draw LSR A LSR A TAX LDA objectPalette,X \ Set edgePixel to logical colour X from the object STA edgePixel \ palette, which we will mask later to contain just the \ single pixel required to draw the edge LDA #0 \ Set P = 0, for use as the low byte of (Q P), in which STA P \ we are going to build the address we need to draw into \ in the dash data \ We now set thisEdge and blockNumber according to the \ edge type: \ \ * Left edge, set: \ \ thisEdge = xPixelCoord + thisEdge / 2 \ blockNumber = thisEdge / 4 \ \ * Right or extra edge, set: \ \ thisEdge = nextEdgeCoord \ blockNumber = blockNumberForNext CPY #1 \ If Y <> 1, jump to draw3 BNE draw3 \ If we get here then Y = 1, so we are drawing the left \ edge LDA thisEdge \ Set A to the scaled scaffold measurement for the left \ edge, which was passed to the routine in thisEdge \ We now set A = A / 2, retaining the sign in A and \ rounding towards zero BPL draw1 \ If A is positive, jump to draw1 SEC \ Set A = A / 2, inserting a set bit into bit 7 to ROR A \ retain the sign of A, and rounding the division up ADC #0 \ towards zero by adding bit 0 of A to the result JMP draw2 \ Jump to draw2 to skip the following instruction .draw1 LSR A \ Set A = A / 2, which will retain the sign of A as we \ know A is positive, rounding the result down towards \ zero .draw2 CLC \ Set thisEdge = A + xPixelCoord ADC xPixelCoord \ = thisEdge / 2 + xPixelCoord STA thisEdge LSR A \ Set blockNumber = A / 4 LSR A \ = thisEdge / 4 STA blockNumber JMP draw4 \ Jump to draw4 .draw3 \ We jump here if Y <> 1, i.e. Y = 0 or 2, so we are \ either drawing an extra edge or the right edge LDA nextBlockNumber \ Set blockNumber = nextBlockNumber STA blockNumber LDA nextEdgeCoord \ Set thisEdge = nextEdgeCoord STA thisEdge CPY #0 \ If Y <> 0, jump to draw7 BNE draw7 .draw4 \ We have now set thisEdge and blockNumber according to \ the edge type, so now we set nextEdgeCoord and \ nextBlockNumber as follows: \ \ nextEdgeCoord = xPixelCoord + nextEdge / 2 \ \ nextBlockNumber = nextEdgeCoord / 4 LDA nextEdge \ Set A to the scaled scaffold measurement for the next \ edge \ We now set A = A / 2, retaining the sign in A and \ rounding towards zero BPL draw5 \ If A is positive, jump to draw5 SEC \ Set A = A / 2, inserting a set bit into bit 7 to ROR A \ retain the sign of A, and rounding the division up ADC #0 \ towards zero by adding bit 0 of A to the result JMP draw6 \ Jump to draw6 to skip the following instruction .draw5 LSR A \ Set A = A / 2, which will retain the sign of A as we \ know A is positive, rounding the result down towards \ zero .draw6 CLC \ Set nextEdgeCoord = A + xPixelCoord ADC xPixelCoord \ = nextEdge / 2 + xPixelCoord STA nextEdgeCoord LSR A \ Set nextBlockNumber = A / 4 LSR A \ = nextEdgeCoord / 4 STA nextBlockNumber \ By this point we have: \ \ * Left edge: \ \ thisEdge = xPixelCoord + thisEdge / 2 \ blockNumber = thisEdge / 4 \ \ * Right or extra edge, set: \ \ thisEdge = nextEdgeCoord \ blockNumber = blockNumberForNext \ \ and we also have the following: \ \ nextEdgeCoord = xPixelCoord + nextEdge / 2 \ nextBlockNumber = nextEdgeCoord / 4 \ \ So we have: \ \ * leftOfEdge contains the fill colour of the object, \ or if the previous edge is within the same pixel \ byte and we are now drawing the next edge, it \ contains the pixel byte from the previous call, \ which contains the previous edge \ \ * rightOfEdge contains the fill colour, or (if we \ need to draw this edge in the same pixel byte as \ the previous edge), it contains the pixel byte \ from the previous call \ \ * edgePixel contains a four-pixel byte in the edge \ colour passed in bits 2-3 of colourData, which we \ will mask later to a single pixel \ \ * thisEdge contains the pixel x-coordinate of the \ edge to draw \ \ * blockNumber contains the dash data block number \ for the edge to draw (as each dash data block is \ four pixels wide) \ \ * nextEdgeCoord and nextBlockNumber contain the \ pixel x-coordinate and dash data block number of \ the next edge, ready to be used in the next call \ to DrawObjectEdge