Includes dash pattern - 1147 bytes (7%)


§1. Line initialisation.

 Used when drawing a line, triangle, circle segment or circle sector.

bear.gif


 Used to initialise variables to track the rasterisation of a straight line.
 e.g. Takes the difference of the coordinates to find the delta X and delta Y of the line.
 Initialises the error term of Bresenham's algorithm.

 On Entry:
   A: vdu index of line end point
   Y: vdu index of line start point
   X: vdu index, where to store results
       in practice X is one of .line1StartPointX
                               .line2StartPointX
                               .line3StartPointX

 On Exit:
   vdu[X+0,X+1]: start point X
   vdu[X+2,X+3]: start point Y
   vdu[X+4,X+5]: abs(deltaX)
   vdu[X+6,X+7]: abs(deltaY)
   vdu[X+8,X+9]: initial error term
   vdu[X+10]: bit 7 is sgn(deltaY) and bit 6 is sgn(deltaX)
   Preserves X
.lineInitialisation = $9872
    PHA                                                 }
    STA .gxrScratchspace3                               }
    TYA                                                 } remember A,Y
    PHA                                                 }
    LDA .gxrScratchspace3                               }

    vdu[X+0,X+1] = vdu[Y+0,Y+1]   (start point X)
    vdu[X+2,X+3] = vdu[Y+2,Y+3]   (start point Y)
    vdu[X+4,X+5] = vdu[A+0,A+1] - vdu[Y+0,Y+1]    (deltaX)
    vdu[X+6,X+7] = vdu[A+2,A+3] - vdu[Y+2,Y+3]    (deltaY)
    JSR .copyAndSubtractCoordinates                     

    PLA                                                 }
    TAY                                                 } recall A,Y
    PLA                                                 }

    Move on by two to do the same for the Y coordinates
    INY                                                 
    INY                                                 Y += 2
    CLC                                                 
    ADC #2                                              A += 2
    INX                                                 
    INX                                                 X += 2
    JSR .copyAndSubtractCoordinates                     
    DEX                                                 X -= 2
    DEX                                                 

    The rest of this routine takes two 16 bit signed numbers:
    
          a = vdu[X+4,X+5]        = deltaX
          b = vdu[X+6,X+7]        = deltaY
    
    and performs the following calculation:
    
      isALarger = (a > b)                 ; remember which is larger
      vdu[X+10] = 128*sgn(b) + 64*sgn(a)  ; remember the sign bits
      a = abs(a)                          ; take absolute value
      b = abs(b)                          ; take absolute value
      temp = max(a, b)
      if isALarger then temp -= 1
      vdu[X+8,X+9] (error term) = temp/2 - b

    Work out which is larger: vdu[X+6,X+7] or vdu[X+4,X+5]
    LDA .vduVariablesStart + 6,X                        
    CMP .vduVariablesStart + 4,X                        
    LDA .vduVariablesStart + 7,X                        
    SBC .vduVariablesStart + 5,X                        
    PHP                                                 carry set if vdu[X+6,X+7] >=
                                                        vdu[X+4,X+5]

    Remember signs of vdu[X+4,X+5] and vdu[X+6,X+7] in top two bits of vdu[X+10]
    LDA .vduVariablesStart + 5,X                        
    ASL                                                 shift top bit of vdu[X+5] into
                                                        vdu[X+10]
    ROR .vduVariablesStart + 10,X                       
    LDA .vduVariablesStart + 7,X                        
    ASL                                                 shift top bit of vdu[X+7] into
                                                        vdu[X+10]
    ROR .vduVariablesStart + 10,X                       
    BPL .doneAbsY                                       

    Negate vdu[X+6,X+7] to get the absolute value
    INX                                                 
    INX                                                 
    JSR .negateVDUX45                                   
    DEX                                                 
    DEX                                                 

.doneAbsY = $98b1
    LDA .vduVariablesStart + 10,X                       get sign of vdu[X+4,X+5]
    ROL                                                 
    BPL +                                               

    Negate vdu[X+4,X+5] to get the absolute value
    JSR .negateVDUX45                                   

+
    Work out which is larger: vdu[X+6,X+7] or vdu[X+4,X+5]
    LDA .vduVariablesStart + 6,X                        
    CMP .vduVariablesStart + 4,X                        
    LDA .vduVariablesStart + 7,X                        
    SBC .vduVariablesStart + 5,X                        
    BMI .fourFiveIsLarger                               

    AY = vdu[X+6,X+7]
    LDA .vduVariablesStart + 7,X                        
    LDY .vduVariablesStart + 6,X                        
    JMP .gotMax                                         

.fourFiveIsLarger = $98d1
    AY = vdu[X+4,X+5]
    LDA .vduVariablesStart + 5,X                        
    LDY .vduVariablesStart + 4,X                        

.gotMax = $98d7
    PLP                                                 
    BMI .skipSubtractOne                                

    AY -= 1
    INY                                                 } [NOTE: use 'CPY #0' for two fewer
                                                        } cycles]
    DEY                                                 }
    BNE +                                               
    SEC                                                 
    SBC #1                                              A -= 1
+
    DEY                                                 Y -= 1

.skipSubtractOne = $98e2
    vdu[X+8,X+9] = AY/2 - vdu[X+6,X+7]
    LSR                                                 
    PHA                                                 
    TYA                                                 
    ROR                                                 

    SEC                                                 
    SBC .vduVariablesStart + 6,X                        
    STA .vduVariablesStart + 8,X                        
    PLA                                                 
    SBC .vduVariablesStart + 7,X                        
    STA .vduVariablesStart + 9,X                        
    RTS                                                 

§2. Copy and subtract coordinates.

 vdu[X,X+1]   = vdu[Y,Y+1]
 vdu[X+4,X+5] = vdu[A,A+1] - vdu[X,X+1]
.copyAndSubtractCoordinates = $98f5
    STA .gxrScratchspace3                               
    LDA .vduVariablesStart,Y                            
    STA .vduVariablesStart,X                            
    LDA .vduVariablesStart+1,Y                          
    STA .vduVariablesStart+1,X                          

    LDY .gxrScratchspace3                               
    SEC                                                 
    LDA .vduVariablesStart,Y                            
    SBC .vduVariablesStart,X                            
    STA .vduVariablesStart+4,X                          
    LDA .vduVariablesStart+1,Y                          
    SBC .vduVariablesStart+1,X                          
    STA .vduVariablesStart+5,X                          
    RTS                                                 

§3. Negate vdu[X+4,X+5].

 On Entry:
   X: vdu offset
 On Exit:
   A,Y: low byte of negated value
.negateVDUX45 = $991b
    SEC                                                 
    LDA #0                                              
    SBC .vduVariablesStart + 4,X                        
    TAY                                                 
    LDA #0                                              
    SBC .vduVariablesStart + 5,X                        
    STA .vduVariablesStart + 5,X                        
    TYA                                                 
    STA .vduVariablesStart + 4,X                        
    RTS                                                 

§4. Move to next pixel along a line.

 Update the current point to move to the next pixel along the line.
 Also updates the error term.

 Notes:
 if the error term is negative, then jump to a routine to handle that, then return
 else:
   add abs(deltaX) to error term
   if the error term is now negative, then call a routine to handle that
   increment or decrement current X coordinate (based on sign of deltaY)

 On Entry:
   the straight line variables are initialised:
      vdu[X+4,X+5]: abs(deltaX)
      vdu[X+6,X+7]: abs(deltaY)
      vdu[X+8,X+9]: error term
      vdu[X+10]:    sign bits of deltaX and deltaY
 On Exit:
   error term updated
   X: incremented by 2
.lineMoveToNextPixel = $992f
    LDA .vduVariablesStart + 9,X                        get error term (high byte)
    BPL .errorTermMinusEqualsAbsDeltaY                  if (error term < 0) then branch

.errorTermPlusEqualsAbsDeltaX = $9934
    CLC                                                 }
    LDA .vduVariablesStart + 8,X                        }
    ADC .vduVariablesStart + 4,X                        }
    STA .vduVariablesStart + 8,X                        } error term += abs(deltaX)
    LDA .vduVariablesStart + 9,X                        }
    ADC .vduVariablesStart + 5,X                        }
    STA .vduVariablesStart + 9,X                        }
    BMI +                                               if (error term < 0) then branch
    JSR .errorTermMinusEqualsAbsDeltaY                  
+
    INX                                                 
    INX                                                 
    LDA .vduVariablesStart + 8,X                        
    BMI .decrementCoordinateX                           increment or decrement Y coordinate
    fall through...

§5. incrementCoordinateX.

.incrementCoordinateX = $9953
    INC .vduVariablesStart,X                            
    BNE +                                               
    INC .vduVariablesStart+1,X                          
+
    RTS                                                 

§6. Move to a new column, updating the X coordinate and the error term.

 error term -= abs(deltaY)
 currentPointX += 1 (or -= 1 depending on the sign of deltaX)
.errorTermMinusEqualsAbsDeltaY = $995c
    SEC                                                 }
    LDA .vduVariablesStart + 8,X                        }
    SBC .vduVariablesStart + 6,X                        }
    STA .vduVariablesStart + 8,X                        } error term -= abs(deltaY)
    LDA .vduVariablesStart + 9,X                        }
    SBC .vduVariablesStart + 7,X                        }
    STA .vduVariablesStart + 9,X                        }

    LDA .vduVariablesStart + 10,X                       sign of deltaX
    ASL                                                 
    BPL .incrementCoordinateX                           increment or decrement X coordinate
    fall through...

§7. decrementCoordinateX.

.decrementCoordinateX = $9975
    LDA .vduVariablesStart,X                            
    BNE +                                               
    DEC .vduVariablesStart+1,X                          
+
    DEC .vduVariablesStart,X                            
    RTS                                                 

§8. clipLineCoordinateX.

.clipLineCoordinateX = $9981
    JSR .swapXAndYCoordinatesOfPointXAndInvertErrorTerm 

    LDA .vduVariablesStart + 10,X                       signs of the two lines
    ASL                                                 carry = sgn(deltaY)   (ignored)
    ASL                                                 carry = sgn(deltaX)
    LDA .vduVariablesStart + 10,X                       
    ROR                                                 put sgn(deltaX) back into the top
                                                        bit in the sgn(deltaY) position.
    STA .vduTempStoreDA                                 clearing the sgn(deltaX) position.
                                                        

    CLC                                                 having done the swap
    BPL .distanceFromleftEdge                           if (sgn(deltaY) >= 0) then branch

    LDA .vduVariablesStart + 2,X                        }
    SBC .vduGraphicsWindowPixelsRightLow                }
    TAY                                                 } YA = Y coordinate - graphics
                                                        } window right edge
    LDA .vduVariablesStart + 3,X                        }
    SBC .vduGraphicsWindowPixelsRightHigh               }
    JMP .clipYCoordinateAndSwapBack                     }

.distanceFromleftEdge = $99a2
    LDA .vduGraphicsWindowPixelsLeftLow                 }
    SBC .vduVariablesStart + 2,X                        } YA = graphics window left edge - Y
                                                        } coordinate
    TAY                                                 }
    LDA .vduGraphicsWindowPixelsLeftHigh                }
    SBC .vduVariablesStart + 3,X                        }

.clipYCoordinateAndSwapBack = $99af
    JSR .clipYCoordinate                                
    JSR .swapXAndYCoordinatesOfPointXAndInvertErrorTerm restore original sense of X and Y
                                                        coordinates
    JMP .errorTermMinusEqualsAbsDeltaY                  

§9. Swap the X and Y coordinates of the current point on a line and invert the error term.

 On Entry:
       vdu[X+0,X+1] = x1 coordinate
       vdu[X+2,X+3] = y1 coordinate
       vdu[X+4,X+5] = x2 coordinate
       vdu[X+6,X+7] = y2 coordinate

 On Exit:
       vdu[X+0,X+1] = y1 coordinate
       vdu[X+2,X+3] = x1 coordinate
       vdu[X+4,X+5] = y2 coordinate
       vdu[X+6,X+7] = x2 coordinate
       vdu[X+8,X+9] ^= $FFFF (i.e. inverted)
.swapXAndYCoordinatesOfPointXAndInvertErrorTerm = $99b8
    INX                                                 }
    TXA                                                 } push X+1
    PHA                                                 }

    Swap X coordinate with Y coordinate
    INX                                                 
    TXA                                                 A = X+2
    DEX                                                 
    DEX                                                 return to original X
    TAY                                                 Y = X+2

[NOTE: the above can be optimised to save 2 bytes:
.swapXAndYCoordinatesOfPointXAndInvertErrorTerm
  INX     ; }
  TXA     ; } A=X+1
  DEX     ; }
  PHA     ; push X+1
  TAY     ; Y=X+1
  INY     ; Y=X+2
 ]

    JSR .exchangeTwoVDUBytes                            this also increments X, Y by two

    Exchange Y coordinates
    INX                                                 
    INX                                                 X+=2
    INY                                                 
    INY                                                 Y+=2
    JSR .exchangeTwoVDUBytes                            X+=2, Y+=2

    Invert error term
    STA .gxrScratchspace3                               [NOTE: Redundant]
    PLA                                                 }
    TAX                                                 } recall X+1 from above
    LDA .gxrScratchspace3                               [NOTE: Redundant]

    Invert error term
    JSR .invertVDUX8                                    invert high byte
    DEX                                                 decrement X and invert low byte
.invertVDUX8 = $99d6
    LDA .vduVariablesStart + 8,X                        error term (high or low)
    EOR #$FF                                            
    STA .vduVariablesStart + 8,X                        error term (high or low)
    RTS                                                 

§10. Clip line to graphics window in Y.

 Use the results of the line initialisation to clip the line to the graphics window.

 Note: The line initialisation leaves us with vduVariables:

     offset    variable name        meaning
     ------------------------------------------
     +0,+1     .line1StartPointX    start point X
     +2,+3     .line1StartPointY    start point Y
     +4,+5     .line1AbsDeltaX      abs(deltaX)
     +6,+7     .line1AbsDeltaY      abs(deltaY)
     +8,+9     .line1ErrorTerm      error term
     +10       .line1Signs          bit 7 is sgn(deltaY) and bit 6 is sgn(deltaX)
.clipLineCoordinateY = $99df
    CLC                                                 
    LDA .vduVariablesStart + 10,X                       get the signs of the line's deltas
    STA .vduTempStoreDA                                 store signs of deltas
    BPL .offsetFromBottomOfGraphicsWindow               if (deltaY >= 0) then branch

    LDA .vduVariablesStart + 2,X                        }
    SBC .vduGraphicsWindowPixelsTopLow                  }
    TAY                                                 } YA = line1StartPointY - graphics
                                                        } window top
    LDA .vduVariablesStart + 3,X                        }
    SBC .vduGraphicsWindowPixelsTopHigh                 }
    JMP .gotHowMuchToClipInY                            

.offsetFromBottomOfGraphicsWindow = $99f7
    LDA .vduGraphicsWindowPixelsBottomLow               }
    SBC .vduVariablesStart + 2,X                        }
    TAY                                                 } YA = graphics window bottom -
                                                        } line1StartPointY
    LDA .vduGraphicsWindowPixelsBottomHigh              }
    SBC .vduVariablesStart + 3,X                        }

.gotHowMuchToClipInY = $9a04
    JSR .clipYCoordinate                                
    JMP .errorTermPlusEqualsAbsDeltaX                   

.clipYCoordinate = $9a0a
    STY .vduTempStoreDE                                 } store how much to clip in Y
    STA .vduTempStoreDF                                 }

    LDA .vduVariablesStart + 2,X                        AY = line1StartPointY
    LDY .vduVariablesStart + 3,X                        

    ASL .vduTempStoreDA                                 shift signs of the deltas
    BCS +                                               if (deltaY < 0) then branch

    line1StartPointY += amount to clip in Y
    ADC .vduTempStoreDE                                 
    STA .vduVariablesStart + 2,X                        
    TYA                                                 
    ADC .vduTempStoreDF                                 
    JMP ++                                              

+
    line1StartPointY -= amount to clip in Y
    SBC .vduTempStoreDE                                 
    STA .vduVariablesStart + 2,X                        
    TYA                                                 
    SBC .vduTempStoreDF                                 
++
    STA .vduVariablesStart + 3,X                        

    LDA .vduVariablesStart + 9,X                        line1ErrorTerm+1 (high byte)
    If top bit of A set, then A=255 else A=0
    PHP                                                 
    LDA #0                                              
    PLP                                                 
    BPL +                                               
    SEC                                                 } [NOTE: could be LDA #255 for one
                                                        } byte saving]
    SBC #1                                              }
+

[NOTE: Alternatively this saves 3 bytes and a few cycles:
  LDA #0
  LDY .vduVariablesStart + 9,X
  BPL +
  LDA #255

]

    STA .vduTempStoreDC                                 
    LSR                                                 
    STA .vduTempStoreDD                                 

    At this point DC/DD is either $0000, or $7FFF, which is added to result of the following
    16 bit multiply
    This is to add rounding, with the result in the top two bytes.

    We multiply the error term by the amount we are clipping by in Y
      which to give details is (line1ErrorTerm + fractional part given in .vduTempStoreDC/D)
    * .vduTempStoreDE/F
    this will give us the new error term

    16 bit x 16 bit = 32 bit multiply (but only top 16 bits used)
    (similar to https://github.com/TobyLobster/multiply_test/blob/main/tests/mult43.a but
    for 16 bit)
    LDY #16                                             loop counter
.multiply16loop = $9a41
    Rotate the four bytes one bit at a time
    LDA .vduTempStoreDD                                 
    ASL                                                 carry = top bit of DD
    ROL .vduVariablesStart + 8,X                        }
    ROL .vduVariablesStart + 9,X                        }
    ROL .vduTempStoreDC                                 } shift result
    ROL .vduTempStoreDD                                 }

    ASL .vduTempStoreDE                                 shift multiplier
    ROL .vduTempStoreDF                                 
    BCC +                                               

    Add multiplicand to result
    CLC                                                 }
    LDA .vduTempStoreDC                                 }
    ADC .vduVariablesStart + 4,X                        }
    STA .vduTempStoreDC                                 } DC/D += vdu[X+4,X+5]
    LDA .vduTempStoreDD                                 }
    ADC .vduVariablesStart + 5,X                        }
    STA .vduTempStoreDD                                 }
    BCC +                                               

    Add one to result
    INC .vduVariablesStart + 8,X                        
    BNE +                                               
    INC .vduVariablesStart + 9,X                        
+

    DEY                                                 
    BNE .multiply16loop                                 loop back until done 16 times
    (end of multiply)

    STA .gxrScratchspace3                               
    LDA .vduVariablesStart + 9,X                        get .line1ErrorTerm high byte
    ASL                                                 
    PHP                                                 }
    LDA .gxrScratchspace3                               } [NOTE: redundant instructions,
                                                        } just use BCC .clipDivide instead?]
    PLP                                                 }
    BPL .clipDivide                                     }

    Store new error term
    LDA .vduTempStoreDC                                 
    STA .vduVariablesStart + 8,X                        store new error term
    LDA .vduTempStoreDD                                 
    STA .vduVariablesStart + 9,X                        store new error term
    RTS                                                 

.clipDivide = $9a89
    16 bit divide: error term / line1AbsDeltaY
    LDY #16                                             loop counter
.divideLoop16 = $9a8b
    ROL .vduTempStoreDC                                 dividend
    ROL .vduTempStoreDD                                 dividend
    ROL .vduVariablesStart + 8,X                        remainder
    ROL .vduVariablesStart + 9,X                        remainder

    SEC                                                 }
    LDA .vduVariablesStart + 8,X                        } temp = remainder - divisor
    SBC .vduVariablesStart + 6,X                        }
    STA .vduTempStoreDE                                 }
    LDA .vduVariablesStart + 9,X                        }
    SBC .vduVariablesStart + 7,X                        }
    BCC .skip                                           if (temp < 0) then branch

    STA .vduVariablesStart + 9,X                        
    LDA .vduTempStoreDE                                 remainder = temp
    STA .vduVariablesStart + 8,X                        
.skip = $9aae
    DEY                                                 
    BNE .divideLoop16                                   loop back until done all 16 bits

    Last iteration of divide
    dividend *= 2
    ROL .vduTempStoreDC                                 
    ROL .vduTempStoreDD                                 
    (end of divide)

    textLeft[X] -= divisor
    SEC                                                 
    LDA .vduVariablesStart + 8,X                        
    SBC .vduVariablesStart + 6,X                        
    STA .vduVariablesStart + 8,X                        

    LDA .vduVariablesStart + 9,X                        
    SBC .vduVariablesStart + 7,X                        
    STA .vduVariablesStart + 9,X                        

    LDA .vduVariablesStart,X                            AY = .line1StartPointX
    LDY .vduVariablesStart+1,X                          
    ASL .vduTempStoreDA                                 
    BCS .subtractDCDDPlusOne                            if (deltaX < 0) then branch

    Add
    SEC                                                 }
    ADC .vduTempStoreDC                                 }
    STA .vduVariablesStart,X                            } .line1StartPointX += 1 + DC/DD
    TYA                                                 }
    ADC .vduTempStoreDD                                 }
    JMP .storeAndReturn                                 }

.subtractDCDDPlusOne = $9ade
    Subtract
    CLC                                                 }
    SBC .vduTempStoreDC                                 }
    STA .vduVariablesStart,X                            } .line1StartPointX -= 1 + DC/DD
    TYA                                                 }
    SBC .vduTempStoreDD                                 }
.storeAndReturn = $9ae7
    STA .vduVariablesStart+1,X                          }
.return16 = $9aea
    RTS                                                 

§11. Plot line.

.plotLine = $9aeb
    JSR .copyDashPatternAndStateIntoPageC               
    LDA .vdu25ParameterPlotType                         
    JSR .plotLineInternal                               
    JSR .copyDashStateBackIntoWorkspace                 
    JMP .setGraphicsCursorPositionAndFinishPLOT         

§12. Plot a line.

 This overrides the OS line plotting, to add the dot-dash pattern and fill pattern features.
 Note that dot-dash and fill patterns can be mixed:

      10 MODE 1
      20 GCOL 16,0
      30 VDU 23,6,&F0;0;0;0;
      40 FOR A=1 TO 200
      50 MOVE 640,512
      60 PLOT 21,RND(1280),RND(1024)
      70 NEXT

 (See https://stardot.org.uk/forums/viewtopic.php?p=341226#p341226 )

 On Entry:
   A: plot type (one of the line plot types)

                     |           |           | Plot  | Plot  |
                     |           | AND $c0:  | First | Last  |
 PLOT Codes          | x4        | EOR $40   | Point | Point | Pattern
 --------------------+-------------------------------------------------
 $00 - $07 ( 0 -  7) | %00000000 | %01000000 |   Y   |   Y   | none
 $08 - $0F ( 8 - 15) | %00100000 | %01000000 |   Y   |   N   | none
 $10 - $17 (16 - 23) | %01000000 | %00000000 |   Y   |   Y   | restarts on each new line
 $18 - $1F (24 - 31) | %01100000 | %00000000 |   Y   |   N   | restarts on each new line
 $20 - $27 (32 - 39) | %10000000 | %11000000 |   N   |   Y   | none
 $28 - $2F (40 - 47) | %10100000 | %11000000 |   N   |   N   | none
 $30 - $37 (48 - 55) | %11000000 | %10000000 |   N   |   Y   | continues on each new line
 $38 - $3F (56 - 63) | %11100000 | %10000000 |   N   |   N   | continues on each new line
.plotLineInternal = $9afa
    ASL                                                 }
    ASL                                                 }
    STA .vduTempStoreDB                                 } x 4
    AND #$C0                                            }
    EOR #$40                                            } see table in comment above to see
                                                        } how plot codes change
    BNE .skipPatternReset                               }

    Reset pattern
    LDA #$80                                            
    STA .currentDotDashPatternBitMask                   mask = top bit
    LDA #0                                              
    STA .currentDotDashPatternByte                      current dot-dash byte = 0
    LDA .currentDotDashPatternBitLength                 
    STA .currentDotDashPatternNumBitsRemaining          remaining = length

.skipPatternReset = $9b14
    Check if the initial point is within the graphics window
    LDX #.vduGraphicsCursorPixelsXLow - .vduVariablesStart graphics cursor = initial point
                                                           of line
    JSR .checkPointXIsWithinGraphicsWindow              

    STA .vduTempStoreDC                                 store result of graphics windows
                                                        boundary check
    .vduTempStoreDC is the result of the initial point boundary check:
          %0000   success (point is within window)
          %0001   graphics cursor X is left of  the left   edge of the graphics window
          %0010   graphics cursor X is right of the right  edge of the graphics window
          %0100   graphics cursor Y is below    the bottom edge of the graphics window
          %1000   graphics cursor Y is above    the top    edge of the graphics window
    BEQ +                                               if (in graphics window) then branch

    Initial point is outside graphics window, so change the plot code to not draw the
    initial point
    Remove top bit from PLOT type [NOTE: the logic is the wrong way round. It should OR in
    (set)
    bit 5. The effect is benign though.]
    LDA #%01111111                                      
    AND .vduTempStoreDB                                 
    STA .vduTempStoreDB                                 
+

    Check if the final point is within the graphics window
    LDX #.vdu25ParameterXLow - .vduVariablesStart       PLOT parameter = final point of line
    JSR .checkPointXIsWithinGraphicsWindow              
    STA .gxrScratchspace1                               store result of graphics windows
                                                        bounds check
    .gxrScratchspace1 is the result of the final point boundary check:
          %0000   success (point is within window)
          %0001   graphics cursor X is left of  the left   edge of the graphics window
          %0010   graphics cursor X is right of the right  edge of the graphics window
          %0100   graphics cursor Y is below    the bottom edge of the graphics window
          %1000   graphics cursor Y is above    the top    edge of the graphics window
    BEQ .pointIsInsideGraphicsWindow                    if (point is within graphics window)
                                                        then branch

    Final point is outside the graphics window, so change the plot code to not draw the final
    point [NOTE: the logic is the wrong way round. It should OR in (set) bit 5. The effect is
    benign though.]
    TAX                                                 
    Remove bit 5
    LDA #%11011111                                      
    AND .vduTempStoreDB                                 
    STA .vduTempStoreDB                                 
    TXA                                                 

    BIT .vduTempStoreDC                                 bit test (like doing an AND) the two
                                                        graphics bounds checks together
.ifNotEqualReturn = $9b37
    BNE .return16                                       if (both points are in the same
                                                        offscreen region) then branch
                                                        (return,
                                                        
                                                        since the line is entirely offscreen)

.pointIsInsideGraphicsWindow = $9b39
    LDY #.vduGraphicsCursorPixelsXLow - .vduVariablesStart start point
    LDA #.vdu25ParameterXLow - .vduVariablesStart       
    LDX #.line1StartPointX - .vduVariablesStart         
    JSR .lineInitialisation                             

    The line initialisation sets up line 1 variables:
       .line1StartPointX: initial and current point X [2 bytes]
       .line1StartPointY: initial and current point Y [2 bytes]
       .line1AbsDeltaX  : abs(deltaX)                 [2 bytes]
       .line1AbsDeltaY  : abs(deltaY)                 [2 bytes]
       .line1ErrorTerm  : Bresenham error term        [2 bytes]
       .line1Signs      : signs of deltaY (top bit) and deltaX (bit 6) [1 byte]

    .vduTempStoreDC holds the result of the initial point boundary check:
          %0000   success (point is within window)
          %0001   graphics cursor X is left of  the left   edge of the graphics window
          %0010   graphics cursor X is right of the right  edge of the graphics window
          %0100   graphics cursor Y is below    the bottom edge of the graphics window
          %1000   graphics cursor Y is above    the top    edge of the graphics window
    LDA .vduTempStoreDC                                 initial point graphics boundary
                                                        check result
    AND #$0C                                            get the Y result
    PHP                                                 remember if zero or not
    LDA .vduTempStoreDC                                 
    PLP                                                 recall
    BEQ .initialPointIsWithinGraphicsWindowY            if (the Y coordinate is inside the
                                                        graphics window) then branch

    Clip Y coordinate
    LDX #.line1StartPointX - .vduVariablesStart         
    JSR .clipLineCoordinateY                            

    Check the point is in the graphics window now it has been clipped
    LDX #.line1StartPointX - .vduVariablesStart         
    JSR .checkPointXIsWithinGraphicsWindow              

    BIT .gxrScratchspace1                               check previous result
    BNE .ifNotEqualReturn                               if (the two ends are now in the same
                                                        offscreen region) then return
                                                        (nothing to draw)

.initialPointIsWithinGraphicsWindowY = $9b5b
    STA .gxrScratchspace3                               result of graphics window boundary
                                                        check for the clipped initial point
    AND #3                                              get just the X result
    PHP                                                 remember if X is in the graphics
                                                        window or not
    LDA .gxrScratchspace3                               
    PLP                                                 recall if X is in the graphics
                                                        window or not
    BEQ .initialPointIsWithinGraphicsWindowX            if (the X coordinate is inside the
                                                        graphics window) then branch

    LDX #.line1StartPointX - .vduVariablesStart         
    JSR .clipLineCoordinateX                            

    Check the point is in the graphics window now it has been clipped
    LDX #.line1StartPointX - .vduVariablesStart         
    JSR .checkPointXIsWithinGraphicsWindow              

.initialPointIsWithinGraphicsWindowX = $9b71
    TAY                                                 }
    BNE .ifNotEqualReturn                               } if (clipped line is still off
                                                        } screen) then return

    Get X and Y as offsets to the final point, taking into account clipping
    LDY #.vdu25ParameterXLow - .vduVariablesStart               } use final point by default
    LDX #.vdu25ParameterYLow - .vduVariablesStart               } (note reversed Y and X in
                                                                } this section)
    LDA .gxrScratchspace1                                       result of final point
                                                                graphics windows bounds check
    BEQ .skipFinalPointCheck                                    if (final point within
                                                                graphics window) then branch
    LDY #.vduGraphicsWindowPixelsRightLow - .vduVariablesStart  use top right of graphics
                                                                window
    LDX #.vduGraphicsWindowPixelsTopLow - .vduVariablesStart    
    BIT .line1Signs                                             
    BPL +                                                       if (deltaY >= 0) then branch
    LDX #.vduGraphicsWindowPixelsBottomLow - .vduVariablesStart use bottom of graphics window
+
    BVC .skipFinalPointCheck                                    if (deltaX >= 0) then branch
    LDY #.vduGraphicsWindowPixelsLeftLow - .vduVariablesStart   use left of graphics window
.skipFinalPointCheck = $9b8c

    Y and X registers are the indices to the X,Y coordinates for the final point

    First get abs(deltaY)
    CLC                                                 
    LDA .vduVariablesStart,X                            
    SBC .line1StartPointY                               start point Y
    BCC +                                               

    Negate A to get absolute value
    ADC #0                                              
    EOR #$FF                                            
+
    STA .vduTempStoreDC                                 store abs(deltaY)

    Get -abs(deltaX)
    CLC                                                 
    LDA .vduVariablesStart,Y                            final clipped X point (low)
    SBC .line1StartPointX                               start point X (low)
    TAX                                                 
    LDA .vduVariablesStart+1,Y                          final clipped X point (high)
    SBC .line1StartPointX+1                             start point X (high)
    BMI ++                                              if negative then branch (no need to
                                                        negate result)

    Negate XA by adding one then inverting the bits
    INX                                                 
    BNE +                                               
    CLC                                                 
    ADC #1                                              
+
    Invert A
    EOR #$FF                                            

    Invert X
    TAY                                                 remember A
    TXA                                                 }
    EOR #$FF                                            } invert X
    TAX                                                 }
    TYA                                                 recall A

++
    STA .vduTempStoreDD                                 } store -abs(deltaX)
    STX .gxrScratchspace1                               } this counts upwards towards zero,
                                                        } used as a loop counter

    LDX #.line1StartPointX - .vduVariablesStart         
    JSR .gxrSetScreenAddressAndSetGraphicsColourMask    get screen address of start point

                                              | Plot  | Plot  |
                                              | First | Last  |
     PLOT Codes              | vduTempStoreDB | Point | Point | Pattern
    -------------------------+------------------------------------------
     $00 - $07   ( 0 -   7)  | %00000000      |   Y   |   Y   | none
     $08 - $0F   ( 8 -  15)  | %00100000      |   Y   |   N   | none
     $10 - $17   (16 -  23)  | %01000000      |   Y   |   Y   | restarts on each new line
     $18 - $1F   (24 -  31)  | %01100000      |   Y   |   N   | restarts on each new line
     $20 - $27   (32 -  39)  | %10000000      |   N   |   Y   | none
     $28 - $2F   (40 -  47)  | %10100000      |   N   |   N   | none
     $30 - $37   (48 -  55)  | %11000000      |   N   |   Y   | continues on each new line
     $38 - $3F   (56 -  63)  | %11100000      |   N   |   N   | continues on each new line

    ASL .vduTempStoreDB                                 
    BCS .skipLinePlotPixel                              skip if initial point is omitted

.plotLineLoop = $9bc7

                                              | Plot  | Plot  |
                                              | First | Last  |
     PLOT Codes              | vduTempStoreDB | Point | Point | Pattern
    -------------------------+------------------------------------------
     $00 - $07   ( 0 -   7)  | %00000000      |   Y   |   Y   | none
     $08 - $0F   ( 8 -  15)  | %01000000      |   Y   |   N   | none
     $10 - $17   (16 -  23)  | %10000000      |   Y   |   Y   | restarts on each new line
     $18 - $1F   (24 -  31)  | %11000000      |   Y   |   N   | restarts on each new line
     $20 - $27   (32 -  39)  | %00000000      |   N   |   Y   | none
     $28 - $2F   (40 -  47)  | %01000000      |   N   |   N   | none
     $30 - $37   (48 -  55)  | %10000000      |   N   |   Y   | continues on each new line
     $38 - $3F   (56 -  63)  | %11000000      |   N   |   N   | continues on each new line

    BIT .vduTempStoreDB                                 test plot type
    BVC .finalPointIncluded                             if (final point included) then branch

    Final point omitted
    Check if we are about to plot the final point
    LDA .gxrScratchspace1                               top byte of -abs(deltaX)
    AND .vduTempStoreDC                                 
    AND .vduTempStoreDD                                 low byte of -abs(deltaX)
    CLC                                                 
    ADC #1                                              add one
    BEQ .return17                                       if (zero) then branch (finished)

    BIT .vduTempStoreDB                                 test plot type (see table above)

.finalPointIncluded = $9bd9
    BPL .linePlotPixel                                  if (first point is included) then
                                                        branch (plot pixel)

    STX .gxrScratchspace3                               index of line1StartPointX

    Move dot-dash line pattern on by one bit, restart when we reach the pattern end
    LDX .currentDotDashPatternByte                      
    LDA .currentDotDashPattern,X                        
    AND .currentDotDashPatternBitMask                   and with mask to see if bit is set
    PHP                                                 
    LSR .currentDotDashPatternBitMask                   shift the current mask one place to
                                                        look at next bit
    BCC +                                               if (mask byte not exhausted) branch

    ROR .currentDotDashPatternBitMask                   sets the mask back to $80 for the
                                                        next byte
    INC .currentDotDashPatternByte                      move to next byte
+
    DEC .currentDotDashPatternNumBitsRemaining          
    BNE .skipResetPattern                               

    Restart pattern
    LDA .currentDotDashPatternBitLength                 
    STA .currentDotDashPatternNumBitsRemaining          remaining = length
    LDA #$80                                            
    STA .currentDotDashPatternBitMask                   set mask to top bit set (the first
                                                        bit of the pattern)
    LDA #0                                              
    STA .currentDotDashPatternByte                      start at first byte of pattern
.skipResetPattern = $9c08

    LDX .gxrScratchspace3                               recall index to line1StartPointX
                                                        [NOTE: could be LDX
                                                        #line1StartPointX - vduStart]
    PLP                                                 get flag to see if the dot pattern
                                                        pixel is set
    BEQ .skipLinePlotPixel                              if (no pixel required) then branch

.linePlotPixel = $9c0e
!if (MACHINE = BBC_B) | (MACHINE = ELECTRON) {
    LDA .vduCurrentPlotByteMask                         current pixel
    AND .vduGraphicsColourByteOR                        and to get colour
    ORA (.vduScreenAddressOfGraphicsCursorCellLow),Y    OR in byte from screen
    STA .vduTempStoreDA                                 store
    LDA .vduCurrentPlotByteMask                         }
    AND .vduGraphicsColourByteEOR                       } plot mode
    EOR .vduTempStoreDA                                 }
    STA (.vduScreenAddressOfGraphicsCursorCellLow),Y    store byte to screen
} else if MACHINE = BBC_B_PLUS {
    JSR .plotPointWithinBoundsAtY
} else {
    +unknown_machine
}

.skipLinePlotPixel = $9c1e
    LDA .line1ErrorTerm+1                               error term (high byte)
    BPL .moveToNextColumn                               

    INC .vduTempStoreDC                                 increment deltaY until it reaches
                                                        zero
    BEQ .return17                                       if (deltaY == 0) then return

    BIT .line1Signs                                     sign of deltaY
    BMI .moveDownARow                                   if (deltaY < 0) then branch

    DEY                                                 move up one row
    BPL .moveUpOrDownDone                               if (not at top of character cell)
                                                        then branch

    JSR .moveGraphicsCursorAddressUpOneCharacterCell    
    JMP .moveUpOrDownDone                               

.return17 = $9c35
    RTS                                                 

.moveDownARow = $9c36
    INY                                                 
    CPY #8                                              
    BNE .moveUpOrDownDone                               if (not at bottom of character cell)
                                                        then branch

    JSR .plotSpriteMoveDownOneCell                      move to next cell

.moveUpOrDownDone = $9c3e
    JSR .gxrSetGraphicsColourMasks                      

    Add to error term
    CLC                                                 }
    LDA .line1ErrorTerm                                 }
    ADC .line1AbsDeltaX                                 }
    STA .line1ErrorTerm                                 } line1ErrorTerm += line1AbsDeltaX
    LDA .line1ErrorTerm+1                               }
    ADC .line1AbsDeltaX+1                               }
    STA .line1ErrorTerm+1                               }
    BPL .moveToNextColumn                               

    JMP .plotLineLoop                                   

.moveToNextColumn = $9c59
    Add one to X coordinate stored in (.gxrScratchspace1, .vduTempStoreDD)
    INC .gxrScratchspace1                               
    BNE +                                               
    INC .vduTempStoreDD                                 
    BEQ .return17                                       if (last column) then branch (return)
+

    BIT .line1Signs                                     sign of original deltaX
    BVS .movePixelToTheLeft                             if (deltaX < 0) then branch

    Move a pixel to the right
    LSR .vduCurrentPlotByteMask                         
    BCC .afterShiftingLeftOrRight                       

    JSR .moveGraphicsCursorAddressTotheRightAndUpdateMask 
    JMP .afterShiftingLeftOrRight                       

.movePixelToTheLeft = $9c71
    Move a pixel to the left
    ASL .vduCurrentPlotByteMask                         
    BCC .afterShiftingLeftOrRight                       
    JSR .moveGraphicsCursorAddressTotheLeftAndUpdateMask 

.afterShiftingLeftOrRight = $9c78
    Subtract from the error term: line1ErrorTerm -= line1AbsDeltaY
    SEC                                                 
    LDA .line1ErrorTerm                                 
    SBC .line1AbsDeltaY                                 
    STA .line1ErrorTerm                                 
    LDA .line1ErrorTerm+1                               }
    SBC .line1AbsDeltaY+1                               } high byte
    STA .line1ErrorTerm+1                               }

    JMP .plotLineLoop                                   

§13. Unused.

 Increment .vduWorkspaceAB,X or decrement it, based on negative flag on entry
.incOrDecWorkspaceAB_X = $9c8e
    BMI .dec                                            
    INC .vduWorkspaceA,X                                
    BNE ++                                              
    INC .vduWorkspaceB,X                                
    RTS                                                 

.dec = $9c99
    LDA .vduWorkspaceA,X                                
    BNE +                                               
    DEC .vduWorkspaceB,X                                
+
    DEC .vduWorkspaceA,X                                
++
    RTS                                                 

§14. Unused.

 Check if .vduWorkspaceABCD == .vduWorkspaceEFGH
.checkIfABCDEqualsEFGH = $9ca5
    LDY #4                                              loop counter
.checkLoop = $9ca7
    LDA .vduWorkspaceA-1,Y                              
    CMP .vduWorkspaceE-1,Y                              
    BNE .checkIsDone                                    
    DEY                                                 
    BNE .checkLoop                                      
.checkIsDone = $9cb2
    RTS                                                 

§15. Move down one cell.

.plotSpriteMoveDownOneCell = $9cb3
    CLC                                                 
    LDA .vduScreenAddressOfGraphicsCursorCellLow        
    ADC .vduBytesPerCharacterRowLow                     
    STA .vduScreenAddressOfGraphicsCursorCellLow        
    LDA .vduScreenAddressOfGraphicsCursorCellHigh       
    ADC .vduBytesPerCharacterRowHigh                    
    BPL +                                               

    SEC                                                 
    SBC .vduScreenSizeHighByte                          loop from bottom of screen to top
+
    STA .vduScreenAddressOfGraphicsCursorCellHigh       
    LDY #0                                              start at the top of the next cell
    RTS                                                 

§16. Copy dot-dash line state and pattern to page C.

 When plotting a line, copy the dot-dash line pattern data into page C for ease of access
.copyDashPatternAndStateIntoPageC = $9ccb
    JSR .getPrivateWorkspaceAddress                     
    LDY #.workspaceOffsetDotDashPatternByte             
    LDX #3 + 8                                          loop counter (3 bytes of dot-dash
                                                        state + 8 bytes of dot-dash pattern)
-
    LDA (.privateWorkspaceLow),Y                        
    STA .currentDotDashPattern,X                        copy from workspace to current
                                                        pattern
    DEY                                                 
    DEX                                                 
    BPL -                                               
    RTS                                                 

§17. Copy dot-dash line state back to private workspace.

 When we are done plotting a line, copy the latest dot-dash state back into the private
 workspace area. This allows the dot-dash state to continue on the next line, if needed.
.copyDashStateBackIntoWorkspace = $9cdc
    JSR .getPrivateWorkspaceAddress                 
    LDY #.workspaceOffsetDotDashPatternByte         
    LDX #2                                          loop counter
-
    LDA .currentDotDashPatternNumBitsRemaining,X    }
    STA (.privateWorkspaceLow),Y                    } workspace[pattern byte] =
                                                    } .currentDotDashPatternByte
    DEY                                             } workspace[dot-dash bit] =
                                                    } .currentDotDashPatternBitMask
    DEX                                             } workspace[bits remaining] =
                                                    } .currentDotDashPatternNumBitsRemaining
    BPL -                                           }

    RTS