Skip to navigation


Drawing objects: FillInsideObject

Name: FillInsideObject [Show more] Type: Subroutine Category: Drawing objects Summary: Fill the object part from the previous edge to the current edge Deep dive: Creating objects from edges
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * DrawObjectEdge (Part 5 of 5) calls FillInsideObject

Arguments: X The number of bash data blocks inside the object that we need to fill blockNumber The block number of the edge to fill up to (i.e. we fill to the left of this block number) leftOfEdge The pixel byte to fill the object with topTrackLine Top track line of the object (higher value, 0 to 79) bottomTrackLine Bottom track line of the object (lower value, 0 to 79)
.FillInsideObject LDA leftOfEdge \ Set A to the byte we want to fill the object with BNE fill1 \ If it is non-zero, jump to fill1 to skip the following \ instruction LDA #&55 \ The fill byte is zero, i.e. colour 0 (black), so set \ A = &55, which is the value we use to represent \ colour 0 (black) in the screen buffer .fill1 STA V \ Store A in V, so V contains the correct fill byte for \ the screen buffer LDA #&7F \ Set T = &7F - topTrackLine SEC \ SBC topTrackLine \ We subtract this value from the start addresses for STA T \ the two dash data blocks that we are going to fill \ concurrently, and add the same value to the offset \ for the bottom line in VV (see the next instruction) \ \ There must be a reason for all these shenanigans, but \ it's currently eluding me ADC bottomTrackLine \ Set VV = T + bottomTrackLine STA VV \ We now calculate the start address of dash data block \ blockNumber - 1, which will be at: \ \ dashData + &80 * (blockNumber - 1) \ \ because the dash data blocks occur every &80 bytes \ from dashData \ \ We do this using the following simplification, where \ A = (blockNumber - 1) \ \ dashData + &80 * A \ = dashData + 256 / 2 * A \ = HI(dashData) << 8 + LO(dashData) + A << 7 \ \ LO(dashData) happens to be zero (as dashData = &3000), \ so we can keep going: \ \ = HI(dashData) << 8 + A << 7 \ = (HI(dashData) << 1 + A) << 7 \ = ((HI(dashData) << 1 + A) << 8) >> 1 \ \ In other words, if we build a 16-bit number with the \ high byte set to HI(dashData) << 1 + A, and then shift \ the whole thing right by one place, we have our result \ \ So this is the same as: \ \ ((HI(dashData) << 1 + blockNumber - 1) << 8) >> 1 \ \ We do this below, storing the 16-bit number in (Q A) LDA blockNumber \ Set A = blockNumber STA U \ Set U = blockNumber CLC \ Set A = A - 1 + HI(dashData) << 1 ADC #HI(dashData)<<1-1 \ = blockNumber - 1 + HI(dashData) << 1 \ \ so our 16-bit number is (A 0), and we want to shift \ right by one place LSR A \ Shift (A 0) right by 1, shifting bit 0 of A into the \ C flag STA Q \ Set Q = A, to store the high byte of the result in Q STA S \ Set S = A, to store the high byte of the result in S LDA #0 \ Shift the C flag into bit 7 of A, so A now contains ROR A \ the low byte of our result \ We now have our result in (Q A), which contains the \ start address of dash data block blockNumber - 1 \ We now subtract T, though as noted above, I'm unclear \ on the reason for this (but the maths all balances out \ in the end, so let's go with it) SEC \ Set (Q P) = (Q A) - T SBC T \ STA P \ We also set the C flag depending on the subtraction EOR #&80 \ Set (S R) = (Q P) - &80 STA R \ \ starting with the low bytes \ \ We can do the subtraction more efficiently by using \ EOR to flip between &xx00 and &xx80, as the dash data \ blocks always start at these addresses BPL fill2 \ We then decrement the high byte, but only if the EOR DEC S \ set the low byte to &80 rather than &00 (if we just \ set it to the latter, the BPL will skip the DEC) .fill2 BCS fill4 \ If the subtraction above didn't underflow, jump to \ fill4 to skip the next two instructions .fill3 DEC Q \ Otherwise decrement the high bytes in (Q P) and (S R) DEC S \ as the low byte subtraction underflowed .fill4 \ By this point, we have: \ \ * (Q P) points to the start address of dash data \ block blockNumber - 1, minus T \ \ * (S R) points to the start address of dash data \ block blockNumber - 2, minus T \ \ So if we fill block (Q P), we will be filling the \ block to the left of the edge, and if we fill block \ (S R), we will be filling the block further to the \ left \ We now enter a loop to fill the object, filling either \ one or both of these blocks at a time LDY U \ Set Y to the block number in U, which starts out as \ blockNumber and goes down by 2 on each loop iteration LDA fillDataOffset-1,Y \ Set A to entry Y - 1 from fillDataOffset, which gives \ us the offset of the bottom line of block Y - 1, \ i.e. blockNumber - 1, adjusted to ensure that filling \ to the left works properly DEY \ Set U = Y - 2 DEY \ = U - 2 STY U CMP bottomTrackLine \ If A < bottomTrackLine, then the bottom of the object BCC fill5 \ is below the bottom of the block, so jump to fill5 to \ do the fill from bottomTrackLine and up ADC T \ Set Y = A + T + C TAY \ = bottom line offset + T + 1 BPL fill6 \ If Y < &80, jump to fill6 to do the fill from track \ line Y and up, so the fill will start from address: \ \ (Q P) + Y = (Q P) + A + T + 1 \ = start address of (blockNumber - 1) - T \ + A + T + 1 \ = start address of (blockNumber - 1) \ + A + 1 \ \ i.e. from track line A in blockNumber - 1 \ If we get here then Y >= &80, which means: \ \ A + T + C >= &80 \ \ A + &7F - topTrackLine + 1 >= &80 \ \ A - topTrackLine >= 0 \ \ A >= topTrackLine \ \ so the bottom line offset is above the top track line, \ which is why we don't do the fill for these two blocks CPX #2 \ If X >= 2, jump to fill8 to move on to the next two BCS fill8 \ blocks to the left RTS \ Return from the subroutine .fill5 LDY VV \ Set Y = VV \ = T + bottomTrackLine \ \ so the fill will start from address: \ \ (Q P) + Y = (Q P) + T + bottomTrackLine \ = start address of (blockNumber - 1) - T \ + T + bottomTrackLine \ = start address of (blockNumber - 1) \ + bottomTrackLine \ \ i.e. from bottomTrackLine in blockNumber - 1 .fill6 \ We now do the fill, filling the relevant blocks from \ offset Y up to offset &7F, so that's: \ \ * From (Q P) + Y to (Q P) + &7F \ \ * And from (S R) + Y to (S R) + &7F if X >= 2 \ \ In the latter case we then reduce X by 2 and loop back \ to do the next two blocks LDA V \ Set A to the byte we want to fill with CPX #2 \ If X < 2, jump to fill9 to fill just one block and BCC fill9 \ return from the subroutine .fill7 STA (P),Y \ Fill the Y-th byte of (Q P) and (S R) with A STA (R),Y INY \ Increment Y to point to the next byte down the screen BPL fill7 \ Loop back until we have filled down to the &7F-th byte .fill8 DEX \ Set X = X - 2 DEX \ \ to move left by two blocks BNE fill3 \ If we haven't filled all the blocks, jump to fill3 to \ fill the next two blocks to the left RTS \ Return from the subroutine .fill9 STA (P),Y \ Fill the Y-th byte of (Q P) with A INY \ Increment Y to point to the next byte down the screen BPL fill9 \ Loop back until we have filled down to the &7F-th byte RTS \ Return from the subroutine