Basic_Sprite_plotter - simondotm/stardot-wiki GitHub Wiki
These routines will allow a sprite to be plotted anywhere on a 20K screen (Mode 2 for example). Simple adjustments can be made to make it work for other screen modes.
-
The sprite must be in the format generated by Swift, see the documentation contained in the Swift download for details.
-
The code listed is from a Swift Project, if you are not assembling and running it within Swift then you will need to make some adjustments.
-
No check is made to see if the sprite is going to be partially (or wholly) off screen. If it goes off screen without you adding in checking code then corruption of your program code may result, or at the very least the sprite will appear partially on the other side of the screen.
-
To make full use in a program you'll need an sprite erase routine.
-
Written in P65 Ophis assembler and specifically for use as a Swift Project
Download a copy of Swift (if you've not already got it) and download the Swift project in the download section below which has all the code. Once extracted (and your Swift installation is set up for P65) from the Zip just load the project into Swift and Run ! This way you'll get about a dozen different sprites to play with as well.
If you can't run Swift (due to your platform of choice) then you'll need to download the sprites and binary data seperatly (see download links at bottom and adjust the source code to either amalgamate it all together and/or change the Swift specific links.
Main
.org $1900 ; load a traditional Beeb start address for a disk system
; we'll load in other code lower than this after we've started
.require "Macros"
.require "AcornConstants" .merge "SpritePlotter"
.require "DroidConstants"
Main:
lda #
<MySpriteObject
sta $70
lda #>MySpriteObject
sta $71
jsr SpritePlotter.PlotSprite
rts
MySpriteObject:
.byte Stryker,24,141 ; id of sprite (see Droid constants), X nd Y Pos
Sprite Plotter
;Main Sprite plot routine, in mode 1
; MEMORY USED
; $72 - $7A directly
; $9F in Times8 Macro
;on entry $70,$71 point to a sprite object structure.
; This is the properties on the sprite, such as which one, x,y etc.
; it does not contain actual sprtie data, that is worked out from the
; sprite id Structure is
;offset meaning
;00 SpriteID ; so supports 128 different sprites (0-127)
;01 X Pos ; it's only 128 as we use this value * 2 to index into the sprite
;02 Y Pos ; data structure pointer table
; Sprite ID's. These index into a look up table of memory locations
; that points to the Sprite graphic data structure.
;Sprite Graphic Structure
;
;offset meaning
;00 width
;01 height
;02->to end graphic data
.require "Macros"
.require "DroidConstants"
;definitions for this file
.alias SpriteObjectStructure $70
.alias SpriteGraphicStructure $72
.alias XOrd $74
.alias YOrd $75
.alias Width $76
.alias Height $77
.alias YScreenAddress $78 ; and 79
.alias SpritePixel $7A
.alias XStartOffset $7B ; remember X offset start, which needs to be the same at start of every new column
.alias ScreenStartHighByte $30
PlotSprite:
; work out screen address that sprite starts at from xy ords
ldy #0
sty YScreenAddress ; just ensure is 0
lda #ScreenStartHighByte
sta YScreenAddress+1
lda(SpriteObjectStructure ),Y ; sprite ID
asl ; get start of sprite graphics, this gets the address of it
tax ; so got the index into the data
clc
lda GameSprites,x
adc #
<GameSprites
sta SpriteGraphicStructure
inx
lda GameSprites,x
adc #>`GameSprites`
sta SpriteGraphicStructure+1 ; so now point to sprite graphic data
lda (SpriteGraphicStructure),Y ; width
sta Width
iny
lda(SpriteObjectStructure ),Y ; X
sta XOrd
lda(SpriteGraphicStructure),Y ; height
sta Height
iny
lda(SpriteObjectStructure),Y ; YOrd
sec
sbc #1
clc
adc Height ; but only to nearest character row start
sta YOrd
and #7 ; put low order bits in X for index addressing
tax
sta XStartOffset ; preserve this for use later
lda YOrd ; then store the other bits 3-7 in YOrd to get screen address of nearest character start row
and #248
sta YOrd
jsr ScreenStartAddress
; now we've got the screen start address, and address of alien, lets plot it
lda YScreenAddress ; put address in code below
sta ScreenPixelAddress+1
lda YScreenAddress+1
sta ScreenPixelAddress+2
clc
lda SpriteGraphicStructure ; move to start of actual graphics data
adc #2 ; to move past width and height
sta SpritePixelAddress+1
lda SpriteGraphicStructure+1
adc #0
sta SpritePixelAddress+2
;ok the main plot bit
PlotXLoop:
ldy Height
dey
PlotLoop:
SpritePixelAddress:
lda $FFFF,Y ;dummy address, will be filled in by code
ScreenPixelAddress:
sta $FFFF,X ; dummy address, will be filled in by code
; are we at a boundary
dex
bpl NotAtRowBoundary ; no, so carry on
;yes we moved to another character row, so we really want this to be the start of next screen row
sec ; we do this by adding &279 to value to get to next row
lda ScreenPixelAddress+1
sbc #$80
sta ScreenPixelAddress+1
lda ScreenPixelAddress+2
sbc #2
sta ScreenPixelAddress+2
ldx #7 ; reset X to 7 (bottom of this character row)
NotAtRowBoundary:
dey
bpl PlotLoop ; have we finished a full column, go to plot loop if not
dec Width
beq EndPlotSprite ; no more to plot, exit routine
; move to next column
clc
lda SpritePixelAddress+1
adc Height
sta SpritePixelAddress+1
lda SpritePixelAddress+2
adc #0
sta SpritePixelAddress+2
lda YScreenAddress
clc
adc #8
sta YScreenAddress
sta ScreenPixelAddress+1
lda YScreenAddress+1
adc #0
sta YScreenAddress+1
sta ScreenPixelAddress+2
ldx XStartOffset
jmp PlotXLoop ;never zero so always branches
EndPlotSprite:
rts
GameSprites:
.incbin "DroidSprites"
LookUp640: ; a 640x multiplication table
.incbin "LookUpTable640"
ScreenStartAddress:
; calculates the screen start address for a mode 2 screen given an X,Y address
; if X or Y go beyond screen limits then returns 0 else the address
; on entry $74=X, $75=Y, returns result in $78,$79
; We use a 640 multiplication look up table
; to speed things up. The Y ord is actually in pixels but due to the way the
; screen is made up by the 6850 we only need the multiplication for character
; rows (every 9th row, i.e. 8 rows per character)
; so divide Y by 8 to get character rows but as there stored as two byte per entry in multiplication table
; each we only need to divide by 4 to get our index into the table
lda YOrd
and #248 ; FIRST REMOVE THE 0 TO 7 VALUE that we don't need to resolve, as screen
; goes down from 0 to 7 ok, just for rest of bits we need to calc 640
lsr
lsr
tay
lda LookUp640,Y
clc
adc YScreenAddress ; lo byte value of the 640 look up
sta YScreenAddress
iny
lda LookUp640,Y ;accumulator now has hi byte
adc YScreenAddress+1
sta YScreenAddress+1 ; so should have base row for Y
; now we have the character row that the sprite is going to plot at
; we need to refine this to a actual row. all we need do is add on
; the lower 3 bits of the Y address that we shifted out with lsr a few lines ago
; and due to the way the address is, we will never get a carry so only a normal
; 8 bit addition
; no need to clc as still clear from earlier
lda YOrd
and #7 ; remove unwanted high order bits leaving us with just the lower 3 bits
clc
adc YScreenAddress ; don't need to add n carry to hi byteas will never occur as
sta YScreenAddress ; the max of 7 added to the start of a character row will never go ovr 255
; right we've now got the Y component of the address, now we've to add in the
; X component. For every X pixel we need to add 8 bytes, for this we won't use
; a look of table as it's quite easy and quickish to multiply by 8.
; It is true that it would be quicker with a look uo table but it would take
; about 320 bytes for only a small gain
`Times8 XOrd, YScreenAddress
rts
; end ScreenStartAddress
Acorn Constants
.alias oswrch $ffee
Macros
general macros not acorn specific
.macro mode
lda #$16
jsr oswrch
lda #_1
jsr oswrch
.macend
.macro lsr3
; shifts the accumulator left parameter 1 number of times
lsr
lsr
lsr
.macend
.macro Times8
; multiply contents of param1 and add result to
; contents of param1 and param1+1
; uses 9F as scratchpad space
; A corrupted, param1 corrupted
lda #0
sta $9F ; clear out hi part of result
clc
asl _1
rol $9F
asl _1
rol $9F
asl _1
rol $9F
; ok got result of multiplication, now add to param2 contents
lda _1
clc
adc _2
sta _2
lda $9F
adc _2+1
sta _2+1
.macend
Droid Constants
.alias Stryker 9
Boot File
MO.2
VDU 19,8,0,0,0,0
*MAIN
LookUpTable640 (download below if required)
00 00 80 02 00 05 80 07 00 0A 80 0C 00 0F 80 11
00 14 80 16 00 19 80 1B 00 1E 80 20 00 23 80 25
00 28 80 2A 00 2D 80 2F 00 32 80 34 00 37 80 39
00 3C 80 3E 00 41 80 43 00 46 80 48 00 4B 80 4D
[The enitre Swift Project](./images/Swift CodeNameDroid.zip "wikilink") (Highly recommended, just load into Swift and run ! )
[ LookUpTable640](./images/Swift SpritePlotter LookUpTable640.zip "wikilink") ( 640 times look up table)
[Sprite data](./images/Swift SpritePlotter DroidSprites.zip "wikilink") (The sample sprites)