Skip to navigation

Revs on the BBC Micro

3D objects: CompareSegments

Name: CompareSegments [Show more] Type: Subroutine Category: 3D objects Summary: Calculate the distance between two objects, in terms of the difference in their segment numbers Deep dive: Placing cars on the track
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * BuildVisibleCar calls CompareSegments * PlaceCarsOnTrack calls CompareSegments

Arguments: X The number of object X Y The number of object Y C flag Determines the accuracy of the arithmetic: * Clear for a 16-bit calculation using objectSegment * For a 24-bit calculation, contains the carry from CompareCarSegments above
Returns: A The distance between the two objects, negative if object X is ahead, positive if object Y is ahead T The same as A C flag How far apart the objects are: * Set if objects are far apart (distance >= 128) * Clear if they are close (distance < 128) N flag The object order (if the objects are close): * Set if object X is ahead by more than 256 * Clear otherwise H Relationship to the starting line: * Bit 7 is clear if the object are quite close (when distance < 256) but are on opposite sides of the starting line * Bit 7 set otherwise
.CompareSegments LDA objectSegmentLo,Y \ Set (A T) = objectSegment for object Y SBC objectSegmentLo,X \ - objectSegment for object X STA T \ \ starting with the low bytes LDA objectSegmentHi,Y \ And then the high bytes SBC objectSegmentHi,X \ \ So (A T) now contains the difference between the two \ objects in terms of their segment numbers, i.e. the \ distance between the two in terms of segment numbers \ \ Let's call this dSegments PHP \ Store the status register on the stack, so the N flag \ on the stack is the sign of the above subtraction, so \ it's set if objectSegmentHi for object Y < \ objectSegmentHi for object X, i.e. if object X is \ ahead by 256 segments or more BPL dist1 \ If the result of the subtraction was positive, jump \ to dist1 to skip the following instruction JSR Absolute16Bit \ The result of the subtraction was negative, so set \ (A T) = |A T| .dist1 STA U \ Set (U T) = (A T) \ = |dSegments| SEC \ Set the C flag to shift into bit 7 of H below BEQ dist2 \ If the high byte of the segment difference is zero, \ jump to dist2 to check the low byte \ If we get here then the high byte of the difference \ is non-zero, so now we need to check whether this is \ down to the objects being close but either side of the \ starting line \ \ This is because the segment number resets to zero at \ the starting line, so objects that are on either side \ of the line will have a big difference in their \ segment numbers even though they are actually quite \ close together PLA \ Flip the N flag in the status register on the stack EOR #%10000000 \ (as the N flag is bit 7 of the status register), so PHP \ the N flag on the stack is the opposite sign to the \ objectSegment subtraction we did above, in other words \ it's now clear if object X is ahead by 256 or more and \ set otherwise \ \ This caters for the situation where the cars are close \ but on either side of the starting line, in which case \ the subtraction we did above will give the wrong \ result, so this flips the order of the two objects to \ be correct \ In the following, the 16-bit number at trackLength \ contains the length of the full track in terms of \ segments LDA trackLength \ Set (A T) = trackLength - (U T) SEC \ = trackLength - |dSegments| SBC T \ STA T \ starting with the low bytes LDA trackLength+1 \ And then the high bytes SBC U BNE dist3 \ If the high byte is non-zero, then that means the \ objects are not just either side of the starting line, \ so they must be far away from each other, so jump to \ dist3 to return from the subroutine with the C flag \ set \ If we get here then the high byte is zero, which means \ the objects are quite close but are either side of the \ starting line CLC \ Clear the C flag .dist2 \ If we get here then the objects are close together \ (the high byte of the difference in segment numbers is \ zero) ROR H \ Set bit 7 of H to the C flag, so it's clear if the \ objects are quite close but on opposite sides of the \ starting line, otherwise it is set LDA T \ If T >= 128, then the difference between the objects CMP #128 \ is >= 128 segments, so jump to dist3 to return from BCS dist3 \ the subroutine with the C flag set \ If we get here then the difference between the objects \ is 127 or less, so the objects are determined to be \ close PLP \ Retrieve the status flags from the stack JSR Absolute8Bit \ Multiply the sign of A by the N flag STA T \ Set T = A LDA T \ Set the N flag according to the value of A CLC \ Clear the C flag RTS \ Return from the subroutine .dist3 \ We get here if the objects are far away from each \ other, i.e. the segment difference between them is \ >= 128 PLP \ Retrieve the status flags from the stack, to return \ from the subroutine SEC \ Set the C flag RTS \ Return from the subroutine