Plot at and pixel position, clipped to the graphics window - 438 bytes (2.6%)


§1. Plot a sprite.

.plotSprite = $a258
    LDY #.workspaceOffsetCurrentSpriteAddressLow        }
    LDA (.privateWorkspaceLow),Y                        } get current sprite address
    INY                                                 }
    ORA (.privateWorkspaceLow),Y                        }
    BNE .plotSpriteInternal                             if (we have a sprite address) then
                                                        branch
    JMP .setGraphicsCursorPositionAndFinishPLOT         

.plotSpriteInternal = $a264
    LDA (.privateWorkspaceLow),Y                        
    TAX                                                 X = sprite address high
    DEY                                                 
    LDA (.privateWorkspaceLow),Y                        A = sprite address low
    STA .privateWorkspaceLow                            } make .privateWorkspace point
    STX .privateWorkspaceHigh                           } to current sprite

    Copy sprite header to workspace (for easier access)
    LDY #5                                              loop counter
-
    LDA (.privateWorkspaceLow),Y                        }
    STA .vduWorkspaceA,Y                                } copy sprite header
    DEY                                                 } to .vduWorkspaceA
    BPL -                                               }

    .vduWorkspaceCD = length of sprite data (including 6 byte header)
    CLC                                                 }
    LDA .privateWorkspaceLow                            }
    ADC #6                                              }
    STA .vduWorkspaceC                                  } .vduWorkspaceCD = sprite size
    LDA .privateWorkspaceHigh                           } (including header)
    ADC #0                                              }
    STA .vduWorkspaceD                                  }

    Reset .vduWorkspaceEFGH, .vduWorkspaceIJ (sprite width), and .vduWorkspaceKL (sprite
    height) to zero
    LDY #7                                              loop counter
    LDA #0                                              
-
    STA .vduWorkspaceE,Y                                
    DEY                                                 
    BPL -                                               

    LDA .vduWorkspaceA                                  sprite width
    STA .vduWorkspaceI                                  .vduWorkspaceI = sprite width-1 (in
                                                        bytes)
    LDA .vduWorkspaceB                                  sprite height
    STA .vduWorkspaceK                                  .vduWorkspaceK = sprite height-1 (in
                                                        pixels)

    .vduWorkspaceIJ = ((width in bytes-1) * pixels per byte) + (pixels per byte - 1) = width
    in pixels - 1
    LDA .vduPixelsPerByteMinusOne                       loop counter
-
    ASL .vduWorkspaceI                                  IJ *= 2
    ROL .vduWorkspaceJ                                  
    LSR                                                 loop counter divided by 2
    BNE -                                               

    Add the number of pixels per byte minus one
    LDA .vduPixelsPerByteMinusOne                       
    ORA .vduWorkspaceI                                  
    STA .vduWorkspaceI                                  I = I OR pixels per byte

    .vduWorkspaceMNOP = PLOT parameter
    LDX #.vdu25ParameterXLow - .vduVariablesStart       source
    LDY #.vduWorkspaceM - .vduVariablesStart            destination
    JSR .copyFourBytesWithinVDUVariables                copy: .vduWorkspaceMNOP = Parameter
                                                        point

    STY .vduTempStoreDA                                 Store Y=.vduWorkspaceQ -
                                                        .vduVariablesStart

    Mask off fractional pixel amounts from X coordinate
    LDA .vduPixelsPerByteMinusOne                       
    EOR #$FF                                            
    AND .vduWorkspaceM                                  
    STA .vduWorkspaceM                                  

    .vduWorkspaceQRST = .vduWorkspaceIJKL + .vduWorkspaceMNOP - .vduWorkspaceEFGH
                      = (width-1,height-1) + PLOT point - zero
                      = top right corner of sprite
    LDX #.vduWorkspaceM - .vduVariablesStart            PLOT point
    LDY #.vduWorkspaceI - .vduVariablesStart            sprite (width-1, height-1)
    LDA #.vduWorkspaceE - .vduVariablesStart            zero
    JSR .calculatePointVduYPlusVduXMinusVduA            

    Check if point .vduWorkspaceMNOP (bottom left of sprite) is within the graphics window
    LDX #.vduWorkspaceM - .vduVariablesStart            
    JSR .checkPointXIsWithinGraphicsWindow              
          %0000   success (gpoint is within window)
          %0001   gpoint X is left of  the left   edge of the graphics window
          %0010   gpoint X is right of the right  edge of the graphics window
          %0100   gpoint Y is below    the bottom edge of the graphics window
          %1000   gpoint Y is above    the top    edge of the graphics window
    BEQ .plotSpriteAfterClippingBottomLeft              if (within the graphics window) then
                                                        branch
    AND #%1010                                          look to see if above or right
    BEQ .clipSpriteBottomLeft                           if (to the left or below the
                                                        graphics window) then branch

    Destination is outside of the graphics window (to the right or above) so nothing
    will get drawn. Finish up.
.finishUp = $a2da
    JMP .setGraphicsCursorPositionAndFinishPLOT         

.clipSpriteBottomLeft = $a2dd
    LDA .vduTempStoreDA                                 check result of graphics window
                                                        boundary check
    PHA                                                 remember it
    AND #%0001                                          
    BEQ .doneLeftClip                                   if (not left of the graphics window)
                                                        then branch

    Clip sprite to left edge of graphics window
    LDX #.vduGraphicsWindowPixelsLeftLow - .vduVariablesStart 
    LDY #.vduWorkspaceE - .vduVariablesStart            
    STY .vduTempStoreDA                                 
    LDA #.vduWorkspaceM - .vduVariablesStart            
    JSR .calculateCoordinateVduYPlusVduXMinusVduA       

    LDY #.vduWorkspaceM - .vduVariablesStart            
    STY .vduTempStoreDA                                 
    JSR .calculateCoordinateVduYPlusVduXMinusVduA       

.doneLeftClip = $a2f6
    PLA                                                 check result of graphics window
                                                        boundary check
    AND #%0100                                          check if below
    BEQ .plotSpriteAfterClippingBottomLeft              if (not below the graphics window)
                                                        then branch

    Clip sprite to bottom edge of graphics window
    LDX #.vduGraphicsWindowPixelsBottomLow - .vduVariablesStart 
    LDY #.vduWorkspaceG - .vduVariablesStart            
    STY .vduTempStoreDA                                 
    LDA #.vduWorkspaceO - .vduVariablesStart            
    JSR .calculateCoordinateVduYPlusVduXMinusVduA       

    LDY #.vduWorkspaceO - .vduVariablesStart            
    STY .vduTempStoreDA                                 
    JSR .calculateCoordinateVduYPlusVduXMinusVduA       

.plotSpriteAfterClippingBottomLeft = $a30d
    Check if point .vduWorkspaceQRST (top right corner of sprite) is within graphics window
    LDX #.vduWorkspaceQ - .vduVariablesStart            
    JSR .checkPointXIsWithinGraphicsWindow              
          %0000   success (gpoint is within window)
          %0001   gpoint X is left of  the left   edge of the graphics window
          %0010   gpoint X is right of the right  edge of the graphics window
          %0100   gpoint Y is below    the bottom edge of the graphics window
          %1000   gpoint Y is above    the top    edge of the graphics window

    BEQ .plotSpriteAfterClippingTopRight                if (within graphics window) then
                                                        branch

    AND #%0101                                          
    BNE .finishUp                                       if (below or left of the graphics
                                                        window) then branch (finish up)

    LDA .vduTempStoreDA                                 check result of graphics window
                                                        boundary check
    PHA                                                 remember it
    AND #%0010                                          
    BEQ .doneRightClip                                  if (not right of the graphics
                                                        window) then branch

    Clip sprite to right edge of graphics window
    LDX #.vduGraphicsWindowPixelsRightLow - .vduVariablesStart 
    LDY #.vduWorkspaceI - .vduVariablesStart            
    STY .vduTempStoreDA                                 
    LDA #.vduWorkspaceQ - .vduVariablesStart            
    JSR .calculateCoordinateVduYPlusVduXMinusVduA       

    LDY #.vduWorkspaceQ - .vduVariablesStart            
    STY .vduTempStoreDA                                 
    JSR .calculateCoordinateVduYPlusVduXMinusVduA       

.doneRightClip = $a331
    PLA                                                 
    AND #%1000                                          
    BEQ .plotSpriteAfterClippingTopRight                if (not above the graphics window)
                                                        then branch

    Clip sprite to the top of the graphics window
    LDX #.vduGraphicsWindowPixelsTopLow - .vduVariablesStart 
    LDY #.vduWorkspaceK - .vduVariablesStart            
    STY .vduTempStoreDA                                 
    LDA #.vduWorkspaceS - .vduVariablesStart            
    JSR .calculateCoordinateVduYPlusVduXMinusVduA       

    LDY #.vduWorkspaceS - .vduVariablesStart            
    STY .vduTempStoreDA                                 
    JSR .calculateCoordinateVduYPlusVduXMinusVduA       

.plotSpriteAfterClippingTopRight = $a348
    All clipping is done

    Divide X pixel coordinates to get byte coordinates again
    LDA .vduPixelsPerByteMinusOne                       
.getByteCoordinates = $a34b
    LSR .vduWorkspaceJ                                  
    ROR .vduWorkspaceI                                  
    LSR .vduWorkspaceF                                  
    ROR .vduWorkspaceE                                  
    LSR                                                 
    BNE .getByteCoordinates                             

    Set screen address for .vduWorkspaceQRST (top right corner of sprite)
    LDX #.vduWorkspaceQ - .vduVariablesStart            
    JSR .setScreenAddress                               

    SEC                                                 
    LDA .vduWorkspaceB                                  
    SBC .vduWorkspaceK                                  
    TAX                                                 X=loop counter
    BEQ .skipAddingSpriteWidths                         

.addWidthToSpriteAddressLoop = $a369
    .vduWorkspaceCD += .vduWorkspaceA
    SEC                                                 
    LDA .vduWorkspaceC                                  
    ADC .vduWorkspaceA                                  
    STA .vduWorkspaceC                                  
    BCC +                                               
    INC .vduWorkspaceD                                  
+
    DEX                                                 loop counter
    BNE .addWidthToSpriteAddressLoop                    

.skipAddingSpriteWidths = $a37b
    .vduWorkspaceCD += .vduWorkspaceA - .vduWorkspaceI
    SEC                                                 
    LDA .vduWorkspaceA                                  
    SBC .vduWorkspaceI                                  
    CLC                                                 
    ADC .vduWorkspaceC                                  
    STA .vduWorkspaceC                                  
    BCC +                                               
    INC .vduWorkspaceD                                  
+
    .vduWorkspaceG = .vduWorkspaceK - .vduWorkspaceG
    SEC                                                 
    LDA .vduWorkspaceK                                  
    SBC .vduWorkspaceG                                  
    STA .vduWorkspaceG                                  

    .vduWorkspaceG += 1
    INC .vduWorkspaceG                                  

    .vduWorkspaceE = .vduWorkspaceI - .vduWorkspaceE
    SEC                                                 
    LDA .vduWorkspaceI                                  
    SBC .vduWorkspaceE                                  
    STA .vduWorkspaceE                                  

    .vduWorkspaceE += 1
    INC .vduWorkspaceE                                  

.plotSpriteLoop = $a3a8
    LDA .vduScreenAddressOfGraphicsCursorCellLow        }
    PHA                                                 }
    LDA .vduScreenAddressOfGraphicsCursorCellHigh       } remember screen address
    PHA                                                 } at the start of the row

    LDA .vduWorkspaceC                                  }
    STA .privateWorkspaceLow                            }
    LDA .vduWorkspaceD                                  } set row start of sprite data
                                                        } address
    STA .privateWorkspaceHigh                           }

    LDX .vduWorkspaceE                                  loop counter
.plotSpriteRowLoop = $a3bb
    LDY #0                                              
    LDA (.privateWorkspaceLow),Y                        read sprite byte
    PHA                                                 
    ORA .gcolModeMask2                                  }
    EOR .gcolModeMask3                                  }
    STA .vduGraphicsColourByteEOR                       } apply GCOL mode
    PLA                                                 }
    ORA .gcolModeMask0                                  }
    EOR .gcolModeMask1                                  }
    LDY .vduGraphicsCursorVerticalOffsetInCell          }

    write byte to screen
!if (MACHINE = BBC_B) | (MACHINE = ELECTRON) {
    ORA (.vduScreenAddressOfGraphicsCursorCellLow),Y    }
    EOR .vduGraphicsColourByteEOR                       }
    STA (.vduScreenAddressOfGraphicsCursorCellLow),Y    write byte to screen
} else if MACHINE = BBC_B_PLUS {
    STA .vduGraphicsColourByteOR                        
    JSR .plotByte                                       write byte to screen with GCOL mode
} else {
    +unknown_machine
}

    INC .privateWorkspaceLow                            }
    BNE +                                               } increment workspace pointer
    INC .privateWorkspaceHigh                           }
+                                                       }

    SEC                                                 
    JSR .moveGraphicsCursorAddressTotheLeftAndUpdateMask 

    DEX                                                 
    BNE .plotSpriteRowLoop                              if (not done) then branch (loop back)

    PLA                                                 }
    STA .vduScreenAddressOfGraphicsCursorCellHigh       } restore original screen address
    PLA                                                 }
    STA .vduScreenAddressOfGraphicsCursorCellLow        }

    .vduWorkspaceCD += sprite width
    SEC                                                 
    LDA .vduWorkspaceC                                  
    ADC .vduWorkspaceA                                  
    STA .vduWorkspaceC                                  
    BCC +                                               
    INC .vduWorkspaceD                                  
+

    Increment offset within cell
    INC .vduGraphicsCursorVerticalOffsetInCell          
    LDY .vduGraphicsCursorVerticalOffsetInCell          
    CPY #8                                              
    BCC +                                               if (not the bottom of the cell) then
                                                        branch

    JSR .plotSpriteMoveDownOneCell                      move down to next cell
    STY .vduGraphicsCursorVerticalOffsetInCell          
+

    Decrement number of rows left to plot
    DEC .vduWorkspaceG                                  
    BNE .plotSpriteLoop                                 if (not done yet) then branch (loop
                                                        back)

    JMP .setGraphicsCursorPositionAndFinishPLOT