BBC Micro Elite

# Dashboard: SCAN (6502SP version)

```       Name: SCAN                                              [View in context]
Type: Subroutine
Category: Dashboard
Summary: Display the current ship on the scanner
Deep dive: The 3D scanner

This is used both to display a ship on the scanner, and to erase it again.

Arguments:

INWK                 The ship's data block

.SCAN

LDA INWK+31            \ Fetch the ship's scanner flag from byte #31

AND #%00010000         \ If bit 4 is clear then the ship should not be shown
BEQ SC5                \ on the scanner, so return from the subroutine (as SC5
\ contains an RTS)

LDX TYPE               \ Fetch the ship's type from TYPE into X

BMI SC5                \ If this is the planet or the sun, then the type will
\ have bit 7 set and we don't want to display it on the
\ scanner, so return from the subroutine (as SC5
\ contains an RTS)

LDA scacol,X           \ Set A to the scanner colour for this ship type from
\ the X-th entry in the scacol table

STA SCANcol            \ Store the scanner colour in SCANcol so it can be sent
\ to the I/O processor with the #onescan command

LDA INWK+1             \ If any of x_hi, y_hi and z_hi have a 1 in bit 6 or 7,
ORA INWK+4             \ then the ship is too far away to be shown on the
ORA INWK+7             \ scanner, so return from the subroutine (as SC5
AND #%11000000         \ contains an RTS)
BNE SC5

\ If we get here, we know x_hi, y_hi and z_hi are all
\ 63 (%00111111) or less

\ Now, we convert the x_hi coordinate of the ship into
\ the screen x-coordinate of the dot on the scanner,
\ using the following (see the deep dive on "The 3D
\ scanner" for an explanation):
\
\   X1 = 123 + (x_sign x_hi)

LDA INWK+1             \ Set x_hi

CLC                    \ Clear the C flag so we can do addition below

LDX INWK+2             \ Set X = x_sign

BPL SC2                \ If x_sign is positive, skip the following

EOR #%11111111         \ x_sign is negative, so flip the bits in A and subtract
ADC #1                 \ 1 to make it a negative number (bit 7 will now be set
\ as we confirmed above that bits 6 and 7 are clear). So
\ this gives A the sign of x_sign and gives it a value
\ range of -63 (%11000001) to 0

.SC2

ADC #123               \ Set A = 123 + x_hi

STA SCANx1             \ Store the x-coordinate in SCANx1 so it can be sent
\ to the I/O processor with the #onescan command

\ Next, we convert the z_hi coordinate of the ship into
\ the y-coordinate of the base of the ship's stick,
\ like this (see the deep dive on "The 3D scanner" for
\ an explanation):
\
\   SC = 220 - (z_sign z_hi) / 4
\
\ though the following code actually does it like this:
\
\   SC = 255 - (35 + z_hi / 4)

LDA INWK+7             \ Set A = z_hi / 4
LSR A                  \
LSR A                  \ So A is in the range 0-15

CLC                    \ Clear the C flag

LDX INWK+8             \ Set X = z_sign

BPL SC3                \ If z_sign is positive, skip the following

EOR #%11111111         \ z_sign is negative, so flip the bits in A and set the
SEC                    \ C flag. As above, this makes A negative, this time
\ with a range of -16 (%11110000) to -1 (%11111111). And
\ another 1 to that value, giving a range of -15 to 0

.SC3

ADC #35                \ Set A = 35 + A to give a number in the range 20 to 50

EOR #%11111111         \ Flip all the bits and store in SC, so SC is in the
STA SC                 \ range 205 to 235, with a higher z_hi giving a lower SC

\ Now for the stick height, which we calculate using the
\ following (see the deep dive on "The 3D scanner" for
\ an explanation):
\
\ A = - (y_sign y_hi) / 2

LDA INWK+4             \ Set A = y_hi / 2
LSR A

CLC                    \ Clear the C flag

LDX INWK+5             \ Set X = y_sign

BMI SCD6               \ If y_sign is negative, skip the following, as we
\ already have a positive value in A

EOR #%11111111         \ y_sign is positive, so flip the bits in A and set the
SEC                    \ C flag. This makes A negative, and as we are about to
\ do an ADC below, the SEC effectively adds another 1 to
\ that value to implement two's complement negation, so
\ we don't need to add another 1 here

.SCD6

\ We now have all the information we need to draw this
\ ship on the scanner, namely:
\
\   X1 = the screen x-coordinate of the ship's dot
\
\   SC = the screen y-coordinate of the base of the
\        stick
\
\   A = the screen height of the ship's stick, with the
\       correct sign for adding to the base of the stick
\       to get the dot's y-coordinate
\
\ First, though, we have to make sure the dot is inside
\ the dashboard, by moving it if necessary

ADC SC                 \ Set A = SC + A, so A now contains the y-coordinate of
\ the end of the stick, plus the length of the stick, to
\ give us the screen y-coordinate of the dot

BPL FIXIT              \ If the result has bit 0 clear, then the result has
\ overflowed and is bigger than 256, so jump to FIXIT to
\ set A to the maximum allowed value of 246 (this
\ instruction isn't required as we test both the maximum
\ and minimum below, but it might save a few cycles)

CMP #194               \ If A >= 194, skip the following instruction, as 194 is
BCS P%+4               \ the minimum allowed value of A

LDA #194               \ A < 194, so set A to 194, the minimum allowed value
\ for the y-coordinate of our ship's dot

CMP #247               \ If A < 247, skip the following instruction, as 246 is
BCC P%+4               \ the maximum allowed value of A

.FIXIT

LDA #246               \ A >= 247, so set A to 246, the maximum allowed value
\ for the y-coordinate of our ship's dot

STA SCANy1             \ Store the y-coordinate in SCANy1 so it can be sent
\ to the I/O processor with the #onescan command

SEC                    \ Set A = A - SC to get the stick length, by reversing
SBC SC                 \ the ADC SC we did above. This clears the C flag if the
\ result is negative (i.e. the stick length is negative)
\ and sets it if the result is positive (i.e. the stick
\ length is negative)

\ So now we have the following:
\
\   X1 = the screen x-coordinate of the ship's dot,
\        clipped to fit into the dashboard
\
\   Y1 = the screen y-coordinate of the ship's dot,
\        clipped to fit into the dashboard
\
\   SC = the screen y-coordinate of the base of the
\        stick
\
\   A = the screen height of the ship's stick, with the
\       correct sign for adding to the base of the stick
\       to get the dot's y-coordinate
\
\   C = 0 if A is negative, 1 if A is positive
\
\ and we can get on with drawing the dot and stick

STA SCANlen            \ Store the stick height in SCANlen so it can be sent
\ to the I/O processor with the #onescan command

ROR SCANflg            \ Rotate the C flag into bit 7 of SCANflg, so bit 7 is
\ the sign bit of the stick length

.SC48

LDX #LO(SCANpars)      \ Set (Y X) to point to the SCANpars parameter block
LDY #HI(SCANpars)

LDA #onescan           \ Send a #onescan command to the I/O processor to draw
JMP OSWORD             \ the ship on the scanner, returning from the subroutine
\ using a tail call
```