Aviator on the BBC Micro

# Drawing lines: DrawCanopyLine (Part 8 of 9)

```       Name: DrawCanopyLine (Part 8 of 9)                            [Show more]
Type: Subroutine
Category: Drawing lines
Summary: Draw a line as a steep vertical slope
Context: See this subroutine in context in the source code
References: No direct references to this subroutine in this source file

.dlin45

\ By the time we get here, the code has been modified to
\ work with the step directions given in bits 6 and 7 of
\ V
\
\ To keep things simple, we will only document the
\ default code, which is for a steep vertical slope with
\ the following:
\
\   * Bit 7 of V is clear, so we step along the x-axis
\     in a positive direction, i.e. to the right
\
\   * Bit 6 of V is clear, so we step along the y-axis
\     in a positive direction, i.e. up the screen
\
\ By this point, we also have the following variables
\ set:
\
\   * (Q P) is the screen address of the pixel row
\     containing pixel (R, S), out by 8 bytes for each
\     row above or below the top of the dashboard
\
\   * I = W + 1, the x-coordinate for the end of the
\     line + 1
\
\   * J = 7, the y-coordinate of the end of the line
\
\ The last two have different values with different line
\ directions, but these are the values for the default
\ case that we're considering here

LDA #159               \ Set Y = 159 - S
SEC                    \
SBC S                  \ This gets added to the screen address in (Q P) that we
TAY                    \ set above, to give the screen address of the starting
\ point at coordinate (R, S)

LDA #255               \ Set RR = 255 - U
SEC                    \        = 255 - |y-delta|
SBC U
STA RR

CLC                    \ Set SS = RR + 1
ADC #1                 \        = 255 - U + 1
STA SS                 \
\ This is the starting value for the slope error

LDA V                  \ If bits 0 and 1 of V are both clear, jump to dlin46
AND #%00000011
BEQ dlin46

CMP #2
BCC dlin46

LDA #255               \ Set SS = 255 for the starting slope error
STA SS

.dlin46

LDA R                  \ Set X = bits 0 and 1 of R, so X is the pixel number
AND #%00000011         \ in the character row for pixel (R, S)
TAX

.dlin47

LDA #%00001000         \ Set A to a pixel byte with pixel 0 set to colour 1
\
\ Gets modified by the ModifyDrawRoutine routine:
\
\   * LDA #8 when colourLogic = %10000000
\
\   * LDA #&80 when colourLogic = %01000000
\
\ In other words, this instruction has already been
\ modified to implement the current colour logic

CPX #0                 \ If X = 0, then the pixel number for point (R, S) is 0,
BEQ dlin49             \ so skip the following loop as the pixel is already in
\ the right place

\ Otherwise we right-shift A by X places to move the
\ pixel to the right place

.dlin48

LSR A                  \ Shift A to the right by one place

DEX                    \ Decrement the shift counter

BNE dlin48             \ Loop back until we have shifted A right by X places,
\ so the pixel is now in the right place for point
\ (R, S) within this pixel row

.dlin49

STA H                  \ Store the pixel byte in H, which contains a single
\ pixel in the correct colour in position X

CLC                    \ Clear the C flag for the addition below

LDX R                  \ Set X = R, so it contains the x-coordinate of the
\ start of the line

.dlin50

LDA H                  \ Set A to the pixel byte for point (R, S) within this
\ pixel row
\
\ Gets modified by the ModifyDrawRoutine routine:
\
\   * LDA H when colourLogic = %01000000
\                           or %10000000
\
\   * LDA #%00001111 when colourLogic = %00000000
\                     and colourCycle = %00001111
\
\   * LDA #%11110000 when colourLogic = %00000000
\                     and colourCycle = %11110000
\
\ In other words, this instruction has already been
\ modified to implement the current colour cycle

.dlin51

ORA (P),Y              \ OR the pixel byte with the current screen contents
\
\ Gets modified by the ModifyDrawRoutine routine:
\
\   * ORA (P),Y when colourLogic = %01000000
\
\   * AND (P),Y when colourLogic = %00000000
\
\ In other words, this instruction has already been
\ modified to implement the current drawing logic

STA (P),Y              \ Update the Y-th byte of (Q P) with the result, which
\ sets 4 pixels to the pixel pattern in A, so this sets
\ the pixel at screen coordinate (R, S) to the current
\ colour

LDA SS                 \ Set A = SS + T
ADC T                  \       = slope error + |x-delta|
\
\ so this updates the slope error as we move up one
\ the screen one pixel at a time

.dlin52

BCS dlin57             \ If the above addition overflowed, then the slope error
\ x-axis
\
\ Gets modified by the DrawCanopyLine routine:
\
\   * BCC dlin57 when bit 7 of V is clear
\
\   * BCC dlin61 when bit 7 of V is set
\
\ In other words, this instruction has already been
\ modified to implement the current drawing direction

STA SS                 \ Set SS = A to store the updated slope error in SS

.dlin53

TYA                    \ Store the current y-coordinate in A
\
\ Gets modified by the DrawCanopyLine routine:
\
\   * TYA when bit 6 of V is clear
\
\   * INY when bit 6 of V is set
\
\ In other words, this instruction has already been
\ modified to implement the current drawing direction

.dlin54

DEY                    \ Decrement Y to move up a pixel row
\
\ Gets modified by the DrawCanopyLine routine:
\
\   * DEY when bit 6 of V is clear
\
\   * TYA when bit 6 of V is set
\
\ In other words, this instruction has already been
\ modified to implement the current drawing direction

AND #7                 \ If A mod 7 <> 0 then we haven't reached the top of the
BNE dlin50             \ 8-row character block, so loop back to dlin50 to draw
\ the next row

\ Otherwise we have reached the top row of the character
\ block, so we now subtract &138 from (Q P) to move to
\ the address of the bottom of the character block in
\ the row above (as each character row in mode 5
\ contains &140 bytes, so this is &140 - 8 to cater for
\ the block we just finished)
\
\ Subtracting &138 is the same as adding &FEC8, so
\ that's what we do now

LDA P                  \ We start by adding &C8 to the low byte in P
CLC

.dlin55

\
\ Gets modified by the DrawCanopyLine routine:
\
\   * ADC #&C8 when bit 6 of V is clear
\
\   * ADC #&38 when bit 6 of V is set
\
\ In other words, this instruction has already been
\ modified to implement the current drawing direction

STA P                  \ Store the updated low byte in P

LDA Q                  \ Then add the high bytes

.dlin56

\
\ Gets modified by the DrawCanopyLine routine:
\
\   * ADC #&FE when bit 6 of V is clear
\
\   * ADC #1 when bit 6 of V is set
\
\ In other words, this instruction has already been
\ modified to implement the current drawing direction

STA Q                  \ Which we store in Q, so now we have:
\
\   (Q P) = (Q P) + &FEC8
\         = (Q P) - &138
\
\ so (Q P) is the address of the end of the character
\ block in the row above

CPY J                  \ If the current y-coordinate in Y <> J, then we have
CLC                    \ not yet reached the y-coordinate of the end of the
BNE dlin50             \ line (which we set in part 7), so loop back to dlin50
\ to keep drawing the line

JMP dlin65             \ Otherwise we have reached the y-coordinate of the end
\ of the line, so jump to dlin65 to process the clipped
\ part of the line, if applicable

.dlin57

\ If we get here then the slope error just overflowed,
\ and we are drawing up the screen (bit 7 of V is clear)
\
\ We reached with a BCS, so we know the C flag is set
\
\ We now need to move the line along the x-axis to the
\ right by 1 pixel, which we do by shifting the single
\ pixel in H to the right, and if it falls off the right
\ end, adjusting the screen address in (Q P) to point to
\ the next character block along

ADC RR                 \ Set SS = A + RR + C
STA SS                 \        = slope error + 255 - |y-delta| + 1
\        = slope error + 256 - |y-delta|
\        = slope error - |y-delta|

INX                    \ Increment X to move along the x-axis to the right

LDA H                  \ Set A to the single pixel byte in H and shift it right
LSR A                  \ to move the pixel along by one place

.dlin58

CMP #%00000000         \ If the pixel byte is non-zero, then the pixel hasn't
BNE dlin60             \ fallen off the end, so jump to dlin60 to skip the
\ following
\
\ Gets modified by the ModifyDrawRoutine routine:
\
\   * CMP #%00000000 when colourLogic = %10000000
\
\   * CMP #%00001000 when colourLogic = %01000000
\
\ In other words, this instruction has already been
\ modified to implement the current drawing logic

LDA P                  \ Set (Q P) = (Q P) + 8
CLC                    \
ADC #8                 \ starting with the low bytes
STA P

.dlin59

LDA #%00001000         \ Set A to a pixel byte with the leftmost pixel set, so
\ we can use this as our new single pixel byte in H
\ below (so shifting across by one character block only
\ moves the single pixel right by one pixel)
\
\ Gets modified by the ModifyDrawRoutine routine:
\
\   * LDA #8 when colourLogic = %10000000
\
\   * LDA #&80 when colourLogic = %01000000
\
\ In other words, this instruction has already been
\ modified to implement the current drawing logic

BCC dlin60             \ And now add the high bytes, so (Q P) now points to the
INC Q                  \ next character block to the right

.dlin60

STA H                  \ Store the updated one-pixel byte in H

CPX I                  \ If the current x-coordinate in X <> I, then we have
CLC                    \ not yet reached the x-coordinate of the end of the
BNE dlin53             \ line (which we set in part 7), so loop back to dlin53
\ to keep drawing the line

BEQ dlin65             \ Otherwise we have reached the x-coordinate of the end
\ of the line, so jump to dlin65 to process the clipped
\ part of the line, if applicable (this BEQ is
\ effectively a JMP as we just passed through a BNE)

.dlin61

\ If we get here then the slope error just overflowed,
\ and we are drawing down the screen (bit 7 of V is set)
\
\ We reached with a BCS, so we know the C flag is set
\
\ We now need to move the line along the x-axis to the
\ left by 1 pixel, which we do by shifting the single
\ pixel in H to the left, and if it falls off the left
\ end, adjusting the screen address in (Q P) to point to
\ the previous character block

ADC RR                 \ Set SS = A + RR + C
STA SS                 \        = slope error + 255 - |y-delta| + 1
\        = slope error + 256 - |y-delta|
\        = slope error - |y-delta|

DEX                    \ Decrement X to move along the x-axis to the left

LDA H                  \ Set A to the single pixel byte in H and shift it left
ASL A                  \ to move the pixel along by one place

.dlin62

CMP #%00010000         \ If the pixel byte is not %00010000, then the pixel
BNE dlin64             \ hasn't fallen off the end, so jump to dlin64 to skip
\ the following
\
\ Gets modified by the ModifyDrawRoutine routine:
\
\   * CMP #%00010000 when colourLogic = %10000000
\
\   * CMP #%00000000 when colourLogic = %01000000
\
\ In other words, this instruction has already been
\ modified to implement the current drawing logic

LDA P                  \ Set (Q P) = (Q P) - 8
SEC                    \
SBC #8                 \ starting with the low bytes
STA P

.dlin63

LDA #%00000001         \ Set A to a pixel byte with the rightmost pixel set, so
\ we can use this as our new single pixel byte in H
\ below (so shifting across by one character block only
\ moves the single pixel left by one pixel)
\
\ Gets modified by the ModifyDrawRoutine routine:
\
\   * LDA #1 when colourLogic = %10000000
\
\   * LDA #16 when colourLogic = %01000000
\
\ In other words, this instruction has already been
\ modified to implement the current drawing logic

BCS dlin64             \ And now subtract the high bytes, so (Q P) now points
DEC Q                  \ to the previous character block to the left

.dlin64

STA H                  \ Store the updated one-pixel byte in H

CPX I                  \ If the current x-coordinate in X <> I, then we have
CLC                    \ not yet reached the x-coordinate of the end of the
BNE dlin53             \ line (which we set in part 7), so loop back to dlin53
\ to keep drawing the line

\ Otherwise we have reached the x-coordinate of the end
\ of the line, so fall through into dlin65 to process
\ the clipped part of the line, if applicable
```