====== Sprite Multiplexer ====== By Fungus/Nostalgia. 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/background priority buffers and add that register to your plot code. 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 txa ;transfer x to a to create index vals sta sort,x ;store it in the sort table inx cpx maxspr+1 ;have we reached 32 yet? 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 ;preset sprite coordinates jsr anim ;animate sprites jsr colors ;adjust sprite 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's covert bit ops page. It comes from the 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's sorted index. Y positions generally do no change by a radical amount from frame to 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,x ;load y index from linked list plus 1 loop2 lda ypos,y ;load a with y position for that index ldy sort,x ;load y index from linked list cmp ypos,y ;compare yposition(index+1,x) to yposition(index,x) bcc swap ;if yposition(index,x) is less than yposition(index+1,x) then swap the indexes inx ;if more than, increment index cpx maxspr+1 ;checked all ypositions? bne loop1 ;no beq end ;yes swap lda sort+1,x ;swap yposition(index+1,x) with yposition(index,x) sta sort,x sty sort+1,x tay dex bpl loop2 ;if not first sprite loop to main inx ;correct index beq loop1 ;restart sort from sprite(index+1,x) 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 ;setup irq. In runtime code main lda timer ;wait for signal, that the buffer swap is complete. sta mloop+1 mloop lda + beq mloop jsr movspr ;move sprites jsr anim ;animate sprites jsr color ;animate colors 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 $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 ;acknowledge any irq that has occured during setup. 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 ;acknowledge irq 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,x ;main index sort algo slep lda ypos,y ldy sort,x ;this sorter uses the previous frame as a prediction buffer. cmp ypos,y ;as y position does not change much from frame to frame. bcc swap ;otherwise, it is a simple swap sort. inx ;our linked list (sort) is sorted in decending order, according cpx #maxspr-1 ;to sprite y positions. 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,y ;this is unrolled for speed. sta ybuf ;this allows us to use only 1 index pointer for our sprite plotter. lda xpos,y ;it is double buffered, to allow runtime code to calculate the sprite 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 ;placing #$ff into the ypos buffer for the corresponding maxc lda ybuf,x ;sprite. It will not be displayed by the raster routine. cmp #$ff beq mxs inx cpx maxspr bne maxc maxs stx cnt ;max sprites this frame count. cpx #$07 ;check if were doing more than 8 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 ;prevents bugs. sta $d003 sta $d005 sta $d007 sta $d009 sta $d00b sta $d00d sta $d00f inc lsbtod ;buffers are swapped, so we can do the next frame now. lda #irq1 ;i.e. lda #$ff sta $d015 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,2,3,4,5,6,7,8 respectively. 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 "overlapping" bugs. irq1 pha ;save registers txa pha tya pha inc $d019 ;acknowledge irq ldx sptr ;get current sprite index hlop1 lda ybuf,x ;get sprite y position sta $d001 ;store sprite y postion. lda xbuf,x ;get sprite x position. sta $d000 ;sta sprite x position. lda mbuf,x ;get sprite x position msb bne no1 ;set msb register lda $d010 ora #%00000001 bne yes1 no1 lda $d010 and #%11111110 yes1 sta $d010 lda pbuf,x ;get sprite image pointer sta $63f8 ;store it, double buffered screen. sta $67f8 lda cbuf,x ;get sprite color sta $d027 ;store sprite color 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 ;yeah, so plot next sprite adc #$02 ;no, so calculate next irq position (+3) sta $d012 ;set it 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 $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 $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 $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 $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 $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 $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 $ffff jmp eirq hlop9 jmp hlop1 done lda #irq0 sta $ffff lda #$fb sta $d012 eirq pla tay pla tax pla rti END