Basic Sprite plotter

From Retrosoftware

(Difference between revisions)
Jump to: navigation, search
(Provisos and restrictions)
(The easy way)
Line 10: Line 10:
==The easy way==
==The easy way==
-
Download a copy of Swift (if you've not already got it) from [http://www.retrosoftware.co.uk/swift here] and download [http://:www.retrosoftware.co.uk/download/file.php?id=38 this] Swift project with 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.
+
Download a copy of [[SWIFT|Swift]] (if you've not already got it) and download [http://:www.retrosoftware.co.uk/download/file.php?id=38 this] [[SWIFT|Swift]] project with all the code. Once extracted (and your [[SWIFT|Swift]] installation is set up for P65) from the Zip just load the project into [[SWIFT|Swift]] and Run ! This way you'll get about a dozen different sprites to play with as well.
 +
 
==The hard way==
==The hard way==
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.
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.

Revision as of 07:35, 28 May 2008

Contents

Basic Sprite Plotter

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.

Provisos and restrictions

  • 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

The easy way

Download a copy of Swift (if you've not already got it) and download this Swift project with 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.

The hard way

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.

Code

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

Downloads

The enitre Swift Project (Highly recommended, just load into Swift and run ! )

LookUpTable640 ( 640 times look up table)

Sprite data (The sample sprites)