Skip to navigation

Revs on the BBC Micro

Drawing objects: ScaleObject

Name: ScaleObject [Show more] Type: Subroutine Category: Drawing objects Summary: Scale an object's scaffold by the scale factors in scaleUp and scaleDown Deep dive: Scaling objects with scaffolds
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * DrawObject calls ScaleObject

This routine is used when drawing objects such as road signs, corner markers and cars. It takes the values from the objectScaffold table, which contain an object's scaffold (i.e. all the essential measurements that we need to build the object), and scales them according to the values of scaleUp and scaleDown. As only scaffold measurements are used when drawing an object, this routine scales the whole object, according to the two scale factors. The value in scaleUp is the numerator of the scale factor, which scales the scaffold up, so bigger values of scaleUp give bigger objects. The value in scaleDown is the denominator of the scale factor, which scales the scaffold down, so bigger values of scaleDown give smaller objects.
Arguments: QQ Index of the first objectScaffold entry for this object II Index of the last objectScaffold entry for this object (where the last entry is index II - 1) scaleUp Numerator scale factor scaleDown Denominator scale factor
Returns: C flag Denotes whether the scaling was successful: * Clear if we manage to scale the scaffold * Set if the scaling of any individual scaffold measurements overflows, in which case we do not draw the object scaledScaffold The scaled scaffold scaledScaffold+8 The scaled scaffold, with each measurement negated
.ScaleObject LDA scaleUp \ Set scaleRange = scaleUp STA scaleRange LSR A \ Set scaleRange+1 = scaleUp >> 1 STA scaleRange+1 \ = scaleUp / 2 LSR A \ Set scaleRange+2 = scaleUp >> 2 STA scaleRange+2 \ = scaleUp / 4 LSR A \ Set scaleRange+3 = scaleUp >> 3 STA scaleRange+3 \ = scaleUp / 8 LSR A \ Set scaleRange+4 = scaleUp >> 4 STA scaleRange+4 \ = scaleUp / 16 LSR A \ Set scaleRange+5 = scaleUp >> 5 STA scaleRange+5 \ = scaleUp / 32 \ So scaleRange + n contains scaleUp / 2^n LDY QQ \ We now loop through the objectScaffold table from \ entry QQ to entry II - 1, so set a loop counter in Y \ to act as an index LDX #0 \ Set W = 0, to be used as an index as we populate the STX W \ scaledScaffold table, incrementing by one byte for \ each loop .prep1 LDA objectScaffold,Y \ Set A to the Y-th scaffold measurement BPL prep2 \ If bit 7 of A is clear, jump to prep2 to do the \ calculation that only uses bits 0-2 of A \ If we get here, bit 7 of A is set, so now we do the \ following calculation, where the value of A from the \ objectScaffold table is %1abbbccc: \ \ A = a * scaleUp/2 + scaleUp/2^b-2 + scaleUp/2^c-2 \ --------------------------------------------- \ 2^scaleDown \ \ = scaleUp * (a/2 + 1/2^b-2 + 1/2^c-2) \ ----------------------------------- \ 2^scaleDown \ \ scaleUp \ = ----------- * (a/2 + 1/2^b-2 + 1/2^c-2) \ 2^scaleDown \ \ scaleUp \ = ----------- * scaffold \ 2^scaleDown \ \ We then store this as the next entry in scaledScaffold \ \ Note that b and c are always in the range 3 to 7, so \ they look up the values we stored in scaleRange above AND #%00000111 \ Set X = bits 0-2 of A TAX \ = %ccc \ = c LDA scaleRange-2,X \ Set T = entry X-2 in scaleRange STA T \ = scaleUp / 2^X-2 \ = scaleUp / 2^c-2 LDA objectScaffold,Y \ Set A to the Y-th scaffold measurement STA U LSR A \ Set X = bits 3-5 of A LSR A \ = %bbb LSR A \ = b AND #%00000111 TAX LDA scaleRange-2,X \ Set A = entry X-2 in scaleRange + T CLC \ = scaleUp / 2^X-2 + scaleUp / 2^c-2 ADC T \ = scaleUp / 2^b-2 + scaleUp / 2^c-2 BIT U \ If bit 6 of U is clear, jump to prep3 BVC prep3 CLC \ If bit 6 of U is set: ADC scaleRange+1 \ \ A = A + scaleRange+1 \ = A + scaleUp / 2 JMP prep3 \ Jump to prep3 .prep2 \ If we get here, bit 7 of the Y-th objectScaffold is \ clear, so we do the following calculation, where \ A is %00000ccc: \ \ A = scaleUp / 2^c-2 \ --------------- \ 2^scaleDown \ \ = scaleUp * 1/2^c-2 \ ----------------- \ 2^scaleDown \ \ = scaleUp \ ----------- * 1/2^c-2 \ 2^scaleDown \ \ scaleUp \ = ----------- * scaffold \ 2^scaleDown \ \ We then store this as the next entry in scaledScaffold TAX \ Set A = entry c-2 in scaleRange LDA scaleRange-2,X \ = scaleUp / 2^c-2 .prep3 LDX scaleDown \ If scaleDown = 0 then the scale factor is 2^scaleDown BEQ prep5 \ = 2^0 = 1, so jump to prep5 to skip the division \ We now shift A right by X places, which is the same as \ dividing by 2^X = 2^scaleDown .prep4 LSR A \ Set A = A >> 1 DEX \ Decrement the shift counter BNE prep4 \ Loop back until we have shifted A right by X places, \ and the C flag contains the last bit shifted out from \ bit 0 of A ADC #0 \ Set A = A + C to round the result of the division to \ the nearest integer .prep5 LDX W \ Set X to W, the index into the tables we are building STA scaledScaffold,X \ Store A in the X-th byte of scaledScaffold EOR #&FF \ Set A = ~A BPL prep6 \ If bit 7 of A is clear, i.e. it was set before the \ EOR, then the result of the scaling was >= 128, which \ is an overflow of the scaling \ \ If the scaling overflows, then the object is too big \ to be drawn, so we jump to prep6 to return from the \ subroutine with the C flag set, so we do not draw this \ object and ignore all the values calculated here CLC \ Store -A in the X-th byte of scaledScaffold+8 ADC #1 STA scaledScaffold+8,X INC W \ Increment the index counter INY \ Increment the loop counter CPY II \ Loop back until Y has looped through QQ to II - 1 BNE prep1 CLC \ Clear the C flag to indicate a successful scaling RTS \ Return from the subroutine .prep6 SEC \ Set the C flag to indicate that scaling overflowed and \ the object should not be drawn RTS \ Return from the subroutine