base:sprite_multiplexer
no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | base:sprite_multiplexer [2015-04-17 04:34] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Sprite Multiplexer ====== | ||
+ | By Fungus/ | ||
+ | |||
+ | The sources are in Turbo Assembler format. | ||
+ | |||
+ | You should be able to have 1 independant color per sprite, and also an independant image for each | ||
+ | sprite. You could also add fore/ | ||
+ | |||
+ | I chose to go for shortness in this routine rather than pure speed. It can be speeded up about | ||
+ | 20% by unrolling all the plotting loops and using self modifed code instead of the second set | ||
+ | of plotting buffers. d010 and d012 storing and comparing could also be precalculated. | ||
+ | |||
+ | Now, the goods. | ||
+ | |||
+ | We are using 32 sprites, so we are going to call this variable (maxspr) from here on. | ||
+ | All of our defined tables will be of length(maxspr). The first table we need, is our linked | ||
+ | list. Our most important table, as we sort this linked list instead of all our tables. | ||
+ | Lets define it. | ||
+ | |||
+ | < | ||
+ | maxspr = $1f | ||
+ | sort = $02 | ||
+ | |||
+ | ldx #$00 ;init x with 00 | ||
+ | loop | ||
+ | sta sort, | ||
+ | | ||
+ | cpx maxspr+1 | ||
+ | bne loop | ||
+ | </ | ||
+ | This routine puts numbers $00 to $1f (32) in the linked list table. Now we have our sort table defined. | ||
+ | The sort buffers can be in any memory area. I chose zeropage for speed. Now lets set up some sprites | ||
+ | and colors in our sprite data buffers. | ||
+ | |||
+ | each buffer takes (maxspr) number of bytes. | ||
+ | < | ||
+ | ypos = $c000 ;sprite y position frame buffer | ||
+ | ybuf = $22 ;sprite y position raster buffer | ||
+ | xpos = $c020 ;sprite x position frame buffer | ||
+ | xbuf = $42 ;sprite x position raster buffer | ||
+ | xmsb = $c040 ;sprite x msb frame buffer | ||
+ | mbuf = $62 ;sprite x msb raster buffer | ||
+ | sprc = $c060 ;sprite color frame buffer | ||
+ | cbuf = $82 ;sprite color raster buffer | ||
+ | sprp = $c080 ;sprite pointer frame buffer | ||
+ | pbuf = $a2 ;sprite pointer raster buffer | ||
+ | |||
+ | jsr movspr | ||
+ | jsr anim ; | ||
+ | jsr colors | ||
+ | </ | ||
+ | Now that we have set up some sprite to show, lets go ahead and precalculate the first frame | ||
+ | to prevent any update bugs, due to excessive sorting of the first frame. This is a special | ||
+ | sorting algorythm, which I discovered on Cadaver' | ||
+ | Imagine games done for Konami and several others. It's nice too see that good old 64 | ||
+ | programmers came up with the idea of a prediction sort that long ago :) The speed of this | ||
+ | sorting technique is unmatched, it uses a prediction, which is really just the previous | ||
+ | frame' | ||
+ | frame. This is ideal for Multiplexer sorting, as it takes less than 2000 cycles to sort 32 sprites. | ||
+ | Otherwise the routine is a simple swap sorter, which is not very complicated at all :) | ||
+ | |||
+ | Here is the routine. | ||
+ | < | ||
+ | ldx #$00 ;init x index to 00 | ||
+ | loop1 ldy sort+1, | ||
+ | loop2 lda ypos, | ||
+ | ldy sort, | ||
+ | cmp ypos, | ||
+ | bcc swap ;if yposition(index, | ||
+ | | ||
+ | cpx maxspr+1 | ||
+ | bne loop1 ;no | ||
+ | beq end ;yes | ||
+ | swap | ||
+ | lda sort+1, | ||
+ | sta sort,x | ||
+ | sty sort+1,x | ||
+ | tay | ||
+ | dex | ||
+ | bpl loop2 ;if not first sprite loop to main | ||
+ | | ||
+ | beq loop1 ;restart sort from sprite(index+1, | ||
+ | end | ||
+ | </ | ||
+ | Quite simple isnt it? | ||
+ | |||
+ | Ok, now lets setup our irq chian, so we can see this bumch of sprites weve just arranged. | ||
+ | < | ||
+ | jsr setirq | ||
+ | </ | ||
+ | In runtime code | ||
+ | < | ||
+ | main lda timer ;wait for signal, that the buffer swap is complete. | ||
+ | sta mloop+1 | ||
+ | mloop lda + | ||
+ | beq mloop | ||
+ | |||
+ | jsr movspr | ||
+ | jsr anim ;animate sprites | ||
+ | jsr color ; | ||
+ | cont jmp main ;loop | ||
+ | |||
+ | setirq | ||
+ | sei ;set interrupt disable | ||
+ | lda #$1b | ||
+ | sta $d011 ;raster irq to 1st half of screen. | ||
+ | lda #$fb | ||
+ | sta $d012 ;irq to happen at line #$fb | ||
+ | lda #<irq0 | ||
+ | sta $fffe ;hardware irq vector low byte | ||
+ | lda #>irq0 | ||
+ | sta $ffff ;hardware irq vector high byte | ||
+ | lda #$1f | ||
+ | sta $dc0d ;turn off all types of cia irq/nmi. | ||
+ | sta $dd0d | ||
+ | lda #$01 | ||
+ | sta $d01a ;turn on raster irq. | ||
+ | lda #$35 | ||
+ | sta $01 ;no basic or kernal | ||
+ | lda $dc0d ; | ||
+ | lda $dd0d | ||
+ | inc $d019 | ||
+ | cli ;clear interrupt disable | ||
+ | rts ;return from subroutine | ||
+ | |||
+ | |||
+ | irq0 | ||
+ | pha ;use stack instead of zp to prevent bugs. | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | inc $d019 ; | ||
+ | ldx #$03 ;wait a few cycles | ||
+ | l1 dex | ||
+ | bpl | ||
+ | inx | ||
+ | stx $d015 ;sprites off = more raster time in top/bottom border | ||
+ | |||
+ | slop ldy sort+1, | ||
+ | slep lda ypos,y | ||
+ | ldy sort, | ||
+ | cmp ypos, | ||
+ | bcc swap ; | ||
+ | inx ;our linked list (sort) is sorted in decending order, according | ||
+ | cpx # | ||
+ | bne slop | ||
+ | beq end | ||
+ | swap | ||
+ | lda sort+1,x | ||
+ | sta sort,x | ||
+ | sty sort+1,x | ||
+ | tay | ||
+ | dex | ||
+ | bpl slep | ||
+ | inx | ||
+ | beq slop | ||
+ | end | ||
+ | |||
+ | ldy sort ;re arrange frame buffers, into the raster buffers. | ||
+ | lda ypos, | ||
+ | sta ybuf ;this allows us to use only 1 index pointer for our sprite plotter. | ||
+ | lda xpos, | ||
+ | sta xbuf ;positions. | ||
+ | lda xmsb,y | ||
+ | sta mbuf | ||
+ | lda sprc,y | ||
+ | sta cbuf | ||
+ | lda sprp,y | ||
+ | sta pbuf | ||
+ | |||
+ | ldy sort+1 | ||
+ | lda ypos,y | ||
+ | sta ybuf+1 | ||
+ | lda xpos,y | ||
+ | sta xbuf+1 | ||
+ | lda xmsb,y | ||
+ | sta mbuf+1 | ||
+ | lda sprc,y | ||
+ | sta cbuf+1 | ||
+ | lda sprp,y | ||
+ | sta pbuf+1 | ||
+ | </ | ||
+ | and so on until max sprites. | ||
+ | < | ||
+ | ldx #$00 ;find # of used sprites (you can remove sprites by | ||
+ | stx sptr ; | ||
+ | maxc lda ybuf, | ||
+ | cmp #$ff | ||
+ | beq mxs | ||
+ | inx | ||
+ | cpx maxspr | ||
+ | bne maxc | ||
+ | maxs stx cnt ;max sprites this frame count. | ||
+ | cpx #$07 ; | ||
+ | bcc maxm ;if not, we want the plotter to stop after 1 irq. | ||
+ | ldx #$07 | ||
+ | maxm stx mnt | ||
+ | |||
+ | lda #$ff ;reset sprites to off screen. | ||
+ | sta $d001 ; | ||
+ | sta $d003 | ||
+ | sta $d005 | ||
+ | sta $d007 | ||
+ | sta $d009 | ||
+ | sta $d00b | ||
+ | sta $d00d | ||
+ | sta $d00f | ||
+ | |||
+ | inc lsbtod | ||
+ | |||
+ | lda #< | ||
+ | sta $fffe ;this one, to turn the sprites back on ;) | ||
+ | lda #> | ||
+ | sta $ffff | ||
+ | lda #$28 | ||
+ | sta $d012 | ||
+ | jmp eirq | ||
+ | </ | ||
+ | Since the buffers have been reordered into proper decending order, we can use unrolled loops for the sprite | ||
+ | plotting. Each plot irq , is for each sprite in the order, 1, | ||
+ | |||
+ | We have a counter (mnt) for 0-7 sprites, as we want to go ahead an plot the first 8 sprites all at | ||
+ | once. We also have another counter (cnt) for the maximum number of sprites to display this frame. | ||
+ | |||
+ | If (mnt) has not been reached yet, each irq branches to the next, to plot the first 8 sprites. | ||
+ | After that, cnt is checked to see if were done plotting sprites. If not, each irq checks the postion of the | ||
+ | sprite to see if it has finished displaying, and to see if its time to be done yet, if it is, it branches to the next irq. | ||
+ | If it is not time yet, it calculates the next raster irq position and sets up the next irq. | ||
+ | |||
+ | By using the previous sprites position, you can properly chain the irqs down the screen, for much less | ||
+ | " | ||
+ | < | ||
+ | irq1 | ||
+ | pha ;save registers | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | inc $d019 ; | ||
+ | ldx sptr ;get current sprite index | ||
+ | hlop1 lda ybuf, | ||
+ | sta $d001 ; | ||
+ | lda xbuf, | ||
+ | sta $d000 ;sta sprite x position. | ||
+ | lda mbuf, | ||
+ | bne no1 ;set msb register | ||
+ | lda $d010 | ||
+ | ora #%00000001 | ||
+ | bne yes1 | ||
+ | no1 lda $d010 | ||
+ | and #%11111110 | ||
+ | yes1 sta $d010 | ||
+ | lda pbuf, | ||
+ | sta $63f8 ; | ||
+ | sta $67f8 | ||
+ | lda cbuf, | ||
+ | sta $d027 ; | ||
+ | inx ;next sprite index | ||
+ | cpx mnt ;lets go to next plot, if < then 8 yet. | ||
+ | bcc hlop2 | ||
+ | cpx cnt ;no more sprites? | ||
+ | bne ok1 | ||
+ | jmp done ;no more sprites. | ||
+ | |||
+ | ok1 stx sptr ;save sprite index | ||
+ | lda $d003 ;get last position of next sprite | ||
+ | clc | ||
+ | adc #$15 ;add 21 lines | ||
+ | cmp $d012 ;we there yet? | ||
+ | bcc hlop2 ; | ||
+ | adc #$02 ;no, so calculate next irq position (+3) | ||
+ | sta $d012 ;set it | ||
+ | lda #< | ||
+ | sta $fffe | ||
+ | lda #>irq2 | ||
+ | sta $ffff | ||
+ | jmp eirq | ||
+ | |||
+ | irq2 | ||
+ | pha ;and so on | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | inc $d019 | ||
+ | ldx sptr | ||
+ | hlop2 lda ybuf,x | ||
+ | sta $d003 | ||
+ | lda xbuf,x | ||
+ | sta $d002 | ||
+ | lda mbuf,x | ||
+ | bne no2 | ||
+ | lda $d010 | ||
+ | ora #%00000010 | ||
+ | bne yes2 | ||
+ | no2 lda $d010 | ||
+ | and #%11111101 | ||
+ | yes2 sta $d010 | ||
+ | lda pbuf,x | ||
+ | sta $63f9 | ||
+ | sta $67f9 | ||
+ | lda cbuf,x | ||
+ | sta $d028 | ||
+ | inx | ||
+ | cpx mnt | ||
+ | bcc hlop3 | ||
+ | cpx cnt | ||
+ | bne ok2 | ||
+ | jmp done | ||
+ | |||
+ | ok2 stx sptr | ||
+ | lda $d005 | ||
+ | clc | ||
+ | adc #$15 | ||
+ | cmp $d012 | ||
+ | bcc hlop3 | ||
+ | adc #$02 | ||
+ | sta $d012 | ||
+ | lda #<irq3 | ||
+ | sta $fffe | ||
+ | lda #>irq3 | ||
+ | sta $ffff | ||
+ | jmp eirq | ||
+ | |||
+ | irq3 | ||
+ | pha | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | inc $d019 | ||
+ | ldx sptr | ||
+ | hlop3 lda ybuf,x | ||
+ | sta $d005 | ||
+ | lda xbuf,x | ||
+ | sta $d004 | ||
+ | lda mbuf,x | ||
+ | bne no3 | ||
+ | lda $d010 | ||
+ | ora #%00000100 | ||
+ | bne yes3 | ||
+ | no3 lda $d010 | ||
+ | and #%11111011 | ||
+ | yes3 sta $d010 | ||
+ | lda pbuf,x | ||
+ | sta $63fa | ||
+ | sta $67fa | ||
+ | lda cbuf,x | ||
+ | sta $d029 | ||
+ | inx | ||
+ | cpx mnt | ||
+ | bcc hlop4 | ||
+ | cpx cnt | ||
+ | bne ok3 | ||
+ | jmp done | ||
+ | |||
+ | ok3 stx sptr | ||
+ | lda $d007 | ||
+ | clc | ||
+ | adc #$15 | ||
+ | cmp $d012 | ||
+ | bcc hlop4 | ||
+ | adc #$02 | ||
+ | sta $d012 | ||
+ | lda #<irq4 | ||
+ | sta $fffe | ||
+ | lda #>irq4 | ||
+ | sta $ffff | ||
+ | jmp eirq | ||
+ | |||
+ | irq4 | ||
+ | pha | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | inc $d019 | ||
+ | ldx sptr | ||
+ | hlop4 lda ybuf,x | ||
+ | sta $d007 | ||
+ | lda xbuf,x | ||
+ | sta $d006 | ||
+ | lda mbuf,x | ||
+ | bne no4 | ||
+ | lda $d010 | ||
+ | ora #%00001000 | ||
+ | bne yes4 | ||
+ | no4 lda $d010 | ||
+ | and #%11110111 | ||
+ | yes4 sta $d010 | ||
+ | lda pbuf,x | ||
+ | sta $63fb | ||
+ | sta $67fb | ||
+ | lda cbuf,x | ||
+ | sta $d02a | ||
+ | inx | ||
+ | cpx mnt | ||
+ | bcc hlop5 | ||
+ | cpx cnt | ||
+ | bne ok4 | ||
+ | jmp done | ||
+ | |||
+ | ok4 stx sptr | ||
+ | lda $d009 | ||
+ | clc | ||
+ | adc #$15 | ||
+ | cmp $d012 | ||
+ | bcc hlop5 | ||
+ | adc #$02 | ||
+ | sta $d012 | ||
+ | lda #<irq5 | ||
+ | sta $fffe | ||
+ | lda #>irq5 | ||
+ | sta $ffff | ||
+ | jmp eirq | ||
+ | |||
+ | irq5 | ||
+ | pha | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | inc $d019 | ||
+ | ldx sptr | ||
+ | hlop5 lda ypos,x | ||
+ | sta $d009 | ||
+ | lda xpos,x | ||
+ | sta $d008 | ||
+ | lda mbuf,x | ||
+ | bne no5 | ||
+ | lda $d010 | ||
+ | ora #%00010000 | ||
+ | bne yes5 | ||
+ | no5 lda $d010 | ||
+ | and #%11101111 | ||
+ | yes5 sta $d010 | ||
+ | lda pbuf,x | ||
+ | sta $63fc | ||
+ | sta $67fc | ||
+ | lda cbuf,x | ||
+ | sta $d02b | ||
+ | inx | ||
+ | cpx mnt | ||
+ | bcc hlop6 | ||
+ | cpx cnt | ||
+ | bne ok5 | ||
+ | jmp done | ||
+ | |||
+ | ok5 stx sptr | ||
+ | lda $d00b | ||
+ | clc | ||
+ | adc #$15 | ||
+ | cmp $d012 | ||
+ | bcc hlop6 | ||
+ | adc #$02 | ||
+ | sta $d012 | ||
+ | lda #<irq6 | ||
+ | sta $fffe | ||
+ | lda #>irq6 | ||
+ | sta $ffff | ||
+ | jmp eirq | ||
+ | |||
+ | irq6 | ||
+ | pha | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | inc $d019 | ||
+ | ldx sptr | ||
+ | hlop6 lda ybuf,x | ||
+ | sta $d00b | ||
+ | lda xbuf,x | ||
+ | sta $d00a | ||
+ | lda mbuf,x | ||
+ | bne no6 | ||
+ | lda $d010 | ||
+ | ora #%00100000 | ||
+ | bne yes6 | ||
+ | no6 lda $d010 | ||
+ | and #%11011111 | ||
+ | yes6 sta $d010 | ||
+ | lda pbuf,x | ||
+ | sta $63fd | ||
+ | sta $67fd | ||
+ | lda cbuf,x | ||
+ | sta $d02c | ||
+ | inx | ||
+ | cpx mnt | ||
+ | bcc hlop7 | ||
+ | cpx cnt | ||
+ | bne ok6 | ||
+ | jmp done | ||
+ | |||
+ | ok6 stx sptr | ||
+ | lda $d00d | ||
+ | clc | ||
+ | adc #$15 | ||
+ | cmp $d012 | ||
+ | bcc hlop7 | ||
+ | adc #$02 | ||
+ | sta $d012 | ||
+ | lda #<irq7 | ||
+ | sta $fffe | ||
+ | lda #>irq7 | ||
+ | sta $ffff | ||
+ | jmp eirq | ||
+ | |||
+ | irq7 | ||
+ | pha | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | inc $d019 | ||
+ | ldx sptr | ||
+ | hlop7 lda ybuf,x | ||
+ | sta $d00d | ||
+ | lda xbuf,x | ||
+ | sta $d00c | ||
+ | lda mbuf,x | ||
+ | bne no7 | ||
+ | lda $d010 | ||
+ | ora #%01000000 | ||
+ | bne yes7 | ||
+ | no7 lda $d010 | ||
+ | and #%10111111 | ||
+ | yes7 sta $d010 | ||
+ | lda pbuf,x | ||
+ | sta $63fe | ||
+ | sta $67fe | ||
+ | lda cbuf,x | ||
+ | sta $d02d | ||
+ | inx | ||
+ | cpx mnt | ||
+ | bcc hlop8 | ||
+ | cpx cnt | ||
+ | bne ok7 | ||
+ | jmp done | ||
+ | |||
+ | ok7 stx sptr | ||
+ | lda $d00f | ||
+ | clc | ||
+ | adc #$15 | ||
+ | cmp $d012 | ||
+ | bcc hlop8 | ||
+ | adc #$02 | ||
+ | sta $d012 | ||
+ | lda #<irq8 | ||
+ | sta $fffe | ||
+ | lda #>irq8 | ||
+ | sta $ffff | ||
+ | jmp eirq | ||
+ | |||
+ | irq8 | ||
+ | pha | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | inc $d019 | ||
+ | ldx sptr | ||
+ | hlop8 lda ybuf,x | ||
+ | sta $d00f | ||
+ | lda xbuf,x | ||
+ | sta $d00e | ||
+ | lda mbuf,x | ||
+ | bne no8 | ||
+ | lda $d010 | ||
+ | ora #%10000000 | ||
+ | bne yes8 | ||
+ | no8 lda $d010 | ||
+ | and #%01111111 | ||
+ | yes8 sta $d010 | ||
+ | lda pbuf,x | ||
+ | sta $63ff | ||
+ | sta $67ff | ||
+ | lda cbuf,x | ||
+ | sta $d02e | ||
+ | inx | ||
+ | cpx mnt | ||
+ | bcc hlop9 | ||
+ | cpx cnt | ||
+ | bne ok8 | ||
+ | jmp done | ||
+ | |||
+ | ok8 stx sptr | ||
+ | lda $d001 | ||
+ | clc | ||
+ | adc #$15 | ||
+ | cmp $d012 | ||
+ | bcc hlop9 | ||
+ | adc #$02 | ||
+ | sta $d012 | ||
+ | lda #<irq1 | ||
+ | sta $fffe | ||
+ | lda #>irq1 | ||
+ | sta $ffff | ||
+ | jmp eirq | ||
+ | hlop9 jmp hlop1 | ||
+ | |||
+ | done lda #<irq0 | ||
+ | sta $fffe | ||
+ | lda #>irq0 | ||
+ | sta $ffff | ||
+ | lda #$fb | ||
+ | sta $d012 | ||
+ | eirq | ||
+ | pla | ||
+ | tay | ||
+ | pla | ||
+ | tax | ||
+ | pla | ||
+ | rti | ||
+ | |||
+ | END | ||
+ | </ |
base/sprite_multiplexer.txt · Last modified: 2015-04-17 04:34 by 127.0.0.1