Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > Sprite multiplexing *with* priorities
2009-01-24 14:40
Bregalad
Account closed

Registered: Jul 2008
Posts: 42
Sprite multiplexing *with* priorities

I'm willing to port a game on the C64 but for sure I'll need more than 8 sprites per screen. The game uses a top-down perspective so sprites that are southern on the screen must show above the sprites that are nothern, else it will look weird.
Unfortunately, most sprite multiplexing tehniques I've seen arround the net seems to kill any priorities, and that's not good.

I guess I can come up with a solution, but I'm not sure how good it is :
- The screen is sepearated into 10 areas of 20 pixel tall
- There is a raster interrupt each 20 pixels that will handle the multiplexing, and the interrupt at line 250 will also be used for the other usual stuff (screen updates, sound code, etc...)
- Each sprite always crosses 2 areas no matter where they are positionned (this assumes Y expanding is never used)

Now during the frame :
In the first area (lines 0-20), the sprites are mapped to hardware sprites with regards to their sorted priorities. If there is more than 8 then the lowest pirority is discarded.

In the second area, the sprites that were already used in the first area cannot be used, so I map the sprites that are still unused to the sprites starting in the second area, regarding to their priorities.

In the third area, all sprites that were used in the first are done being displayed and I can re-map them to sprites of the third area according to their priorities, etc....

Now the priorities are not matched between areas, but at least they are inside each area. Also the number of interrupts is constant, and everything can be pre-calculed during the non-display time, so that interrupts just do a few writes each 20 scanlines which is not too bothersome and allow it to be mixed with other raster split without too much trouble.

I know Cadavers said it was a bad idea to split the screen with areas, but I can't come with anything else. I could use the generic method in a way so that top sprites are lowest priorities than bottom sprites, and hoping it won't look too weird.
 
... 61 posts hidden. Click here to view all posts....
 
2009-01-24 18:01
Oswald

Registered: Apr 2002
Posts: 5094
"sprites that are southern on the screen must show above the sprites that are nothern, else it will look weird."

so display the sprites in the right order for that (8->1)? at every 8th sprite it will bug, but it comes for free.

edit: and read cadaver's sprite multiplexing tutorial. zone split with fixed irq places for this is a bad approach.
2009-01-24 18:05
cadaver

Registered: Feb 2002
Posts: 1160
If you want some extra insurance against the wrap-bug you could reset the physical-sprite assignment index back to 8 (= least priority), whenever you have no overlapping sprites for a while. Never done this in practice, but theoretically it should work??
2009-01-24 18:23
Bregalad
Account closed

Registered: Jul 2008
Posts: 42
I have read Cadaver's tutorial before posting this, don't worry. But it doesn't cover the priority part.

I know he said the area split is a bad idea, but why ? He said it worked for Metal Warriors 2/3 (is that right ?) and I like the idea of having fixed IRQ at fixed places which sounds easier than to have an IRQ for each new sprite which means a lot of IRQs and more likely to get glitches.

Yes I could make it so that sprites goes from 8 to 1 and then reset to 8 so that the priority would look mostly good. If I can somoehow detect that there is no overlapping sprites for a while, I could reset the index to 8. I guess I could try that as well and see how it turns.
2009-01-24 18:44
cadaver

Registered: Feb 2002
Posts: 1160
Actually Metal Warrior 1-3 never used zone splitted or fixed IRQ's, but an inaccurate bucket sorting method, where Y was simply divided by 8, and that's what the tutorial was referring to if I remember right.
2009-01-24 18:58
Oswald

Registered: Apr 2002
Posts: 5094
resetting to sprite nr 8: all you have to do is to search for a virtual sprite which is atleast 21 lines away from the "currently" used sprite 8. so if you hit sprite 8, then look up the next 8 virtual sprites and check if one of them is farther than 21 lines if it is it can be resetted to physical nr 8. dynamic irqs are ESSENTIAL for this as they can pack sprites more densely and no further problems arise like caring about the fixed irq location. fixed irqs issue heavy limitations, if sprite nr 8 is used in one of them you have to wait 40 lines (worst case) for the next chance to use it. compare this to the constant 21 lines of dynamic irqs.

check the link, and spend your time understanding those multiplexers. its really not rocket science, also we're here to explain.
2009-01-24 20:06
Bregalad
Account closed

Registered: Jul 2008
Posts: 42
Quote:
Actually Metal Warrior 1-3 never used zone splitted or fixed IRQ's, but an inaccurate bucket sorting method, where Y was simply divided by 8, and that's what the tutorial was referring to if I remember right.

OK this clear things up thank you for pointing that.

In my current version of the game (on the NES) I use a modified bubble sort on all object so that their sprites are done in an ascending order (southern object with top priorities), and also uses a divide-by-8 method. If both coordinates divided by 8 are equal, I exchange them on odd frames only so I get nice flickering (something necessary on the NES if there is more than 8 sprites on the same line) and it works fine.

I guess chances are that you experienced guys are right about that area split method is bad, but I'd like to know why exactly. It does sound like in some case it would be bad, for example if there is 8 sprites in an area and 2 in the area below it, the latter 2 won't show at all if I do it in the way I describe it above. Is it why it is bad ?

So I guess I'm listening you and am going to use dynamic IRQs. Fortunately I wasn't planning to do any raster effecs (other than sprite multiplexing) during gameplay, but I plan to do some outside of gameplay. In that cases it would be a headache to try to have both dynamic IRQs and static IRQs for BG background effects, so I would be limited to 8 sprites here. This isn't too much bothering, but I'd then have to have 2 sprite engines and I don't like that but it doesn't matter I'll deal with that.
2009-01-24 20:38
Oswald

Registered: Apr 2002
Posts: 5094
you can use the CIA timers for 2 more interrupt sources, and more effects on the screen.

"if there is 8 sprites in an area and 2 in the area below it, the latter 2 won't show at all if I do it in the way I describe it above"

thats why its bad. dynamic irqs can show all 10 sprites in that case.
2009-02-02 17:58
Bregalad
Account closed

Registered: Jul 2008
Posts: 42
OK I've been working on it and it's really insane to get something working. But I'm close to it I guess, but I have problems with how the interrupt fires. I do the following :

I always fire an interrupt at line 255, that I call the "VBlank" interrupt.
At the start of the interrupt, the sprites for the frame to come are sorted, and everything is pre-calculated and copied into buffers for the following frame, so that the main code can maze new sprites while the old are displayed.

A couple of lines before any sprite, an interrupt is triggered and the data for that particual sprite is copied to the actual VIC registers. After that it checks if the following interrupt is very close and if so it loops automatically without having a second interrupt to happen. If the next interrupt is the VBlank and is very close I jump to it automatically too.

The problem I have is that right after I do a "cli" instruction in the VBlank interrupt (after sorting all sprites, assigned them a hardware number and initied the next interrupt), the first interrupt fires straight away even if it's not time yet. Also the VBlank interrupt was already acknownledged before I do that cli so this shouldn't be the problem. This happen on scanline 270 or so, and the interrupt is supposed to happen 4 lines before the first sprite.

I will post the code that causes me problems (I can't post the whole programm because it would be too long). This is what happen after all sprites are sorted, their hardware positions are determined and the IRQ lines that will happen are decided. In case of the variable "SpriteRasterIndex" is here to determine what causes the next IRQ, if it's a positive number it's the number of the sprite that caused the IRQ, if $ff it's for VBlank interrupt.
-	ldy SortOrder,X		;Copy Y pos, X posL, Color and Tile Number to sorted buffers
	lda SpritePosY.w,Y
	sta SpriteSortedPosY.w,X
	lda SpritePosXL.w,Y	;So that they are accedded faster during IRQ
	sta SpriteSortedPosXL.w,X
	lda SpriteFlags.w,Y	;And can be written again during the frame by the main programm
	and #$0f
	sta SpriteSortedFlags.w,X
	lda SpriteTileNmr.w,Y
	sta SpriteSortedTileNmr.w,X
	dex
	bpl -
	inx
	stx SpriteReadyFlag	;Clear the pending flag

OldSprites
	ldy #$00
-	lda InterruptLine.w,Y	;Load the first valid interrupt (nonzero)
	bne +
	iny
	cpy #SpriteAmount
	bne -			;If no valid interrupt
	lda #$ff		;...we set $ff for VBlank interrupt
+	sta $d012		;Initislise the first interrupt
	cmp #$ff
	beq +
	tya
+	sta SpriteRasterIndex	;The next IRQ is a sprite IRQ if line is not $ff, else it's the VBlank IRQ
	stx $d015		;No sprite visible before the first interrupt
	cli			;Enable the interrupts
	rts

Here at the CLI the first interrupt occurs immediately.

PS : Where can I found info about the CIA timers ? I can't find any in Commodore's doccumentation nor on the Wiki. I only found how to disable them (and I do that). Are they precise enough to get some screen effects ? Can they be routed on the NMI instead, because here I already have two IRQ possiblilities (sprite/VBlank), if there were 3 it would become really a headache.
2009-02-02 18:02
Oswald

Registered: Apr 2002
Posts: 5094
you should show the interrupt handling code instead of the sprite messing. maybe there should be an rti instead of the rts? and if so you dont restore (&save) the registers. also you dont need to do cli. rti will clear the I flag.

furthermore, do you realsie that the raster counter is 9 bit wide, including the topmost bit in d011 ? if you write d011 it can set the 9th bit of the raster counter to high, and the irq will occuer at >255 line.
2009-02-02 18:18
Bregalad
Account closed

Registered: Jul 2008
Posts: 42
Yeah I write something to $d011 with bit 7 clear so that I always trigger interrupts in the visible part of the screen (or on the bottom of the screen). Do I have to re-write $d011 regularly to prevent interrupts to be triggered during VBlank ? And yes I do a cli instruction so that after the sprites are sorted and ready to be displayed, the VBlank IRQ can continue and be interrupted by sprite IRQ if it needs so. Without the cli, the sprite IRQ would be blocked as long as the VBlank IRQ does not return.

I can post the IRQ handler if you want :
IRQ	inc $d019	;Acknownledge the raster IRQ
	pha
	txa
	pha
	tya
	pha		;Check if the IRQ is caused by the sprite multiplexing
	ldx SpriteRasterIndex
	bpl SpriteIRQ	;Or by the end of the frame (raster position $ff)
MainIRQ
	jsr SpriteMultiplexer
	jsr InitSprites
	jsr SetSprites
;	jsr MoveStars
	jsr MoveCenter
	lda FrameCtr
	eor #$01
	sta FrameCtr
	pla
	tay
	pla
	tax
	pla
NMI	rti

SpriteIRQ
	ldy SpriteHWAssign.w,X
	lda SpriteSortedFlags.w,X
	sta $d027,Y			;Color
	lda SpriteSortedTileNmr.w,X
	sta $7f8,Y			;Tile number
	tya
	asl A
	tay
	inc $d020
	lda SpriteSortedPosY.w,X
	sta $d001,Y
	lda SpritePosXL.w,X
	sta $d000,Y
	lda D017Buffer.w,X
	sta $d017
	lda D01dBuffer.w,X
	sta $d01d
	lda D01bBuffer.w,X	;Copy all flags
	sta $d01b
	lda D01cBuffer.w,X
	sta $d01c
	lda D015Buffer.w,X
	sta $d015
	lda D010Buffer.w,X
	sta $d010
	dec $d020

-	inx
	cpx #SpriteAmount	;Last sprite ?
	bcs _lastInt
	lda InterruptLine.w,X
	beq -			;If raster line is 0, we should ignore it
	stx SpriteRasterIndex	;Copy valid index and rasterline
	sta $d012
	cmp #$ff
	beq _lastInt		;If value is $ff, then it's the last interrupt of the frame
	sec
	sbc #$02		;If a new interrupt should occur in less than 2 scanlines
	cmp $d012		;Do it straight away
	bcs +
	jmp SpriteIRQ

--	lda #$ff
	cmp $d012
	bne _lastInt
-	jmp MainIRQ

_lastInt
	bit $d011
	bmi -		;If we somehow missed the main IRQ make sure we jump to it right away
	lda #$fd
	cmp $d012	;If rasterline is $fe or $ff go to main IRQ after a small delay (I don't want to miss it)
	bcc --
	lda #$ff
	sta $d012
	sta SpriteRasterIndex
+	pla
	tay
	pla
	tax
	pla
	rti
Previous - 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 - Next
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
LightSide
Raf/Vulture Design
BYB/Hokuto Force
t0m3000/hf^boom!^ibx
zscs
megasoftargentina
HCL/Booze Design
Acidchild/Padua
deeL/DD
B.A./QUANTUM
aNdy/AL/Cosine
REBEL 1/HF
Guests online: 117
Top Demos
1 Next Level  (9.7)
2 13:37  (9.7)
3 Mojo  (9.7)
4 Coma Light 13  (9.6)
5 Edge of Disgrace  (9.6)
6 What Is The Matrix 2  (9.6)
7 The Demo Coder  (9.6)
8 Uncensored  (9.6)
9 Comaland 100%  (9.6)
10 Wonderland XIV  (9.6)
Top onefile Demos
1 No Listen  (9.6)
2 Layers  (9.6)
3 Cubic Dream  (9.6)
4 Party Elk 2  (9.6)
5 Copper Booze  (9.6)
6 Dawnfall V1.1  (9.5)
7 Rainbow Connection  (9.5)
8 Onscreen 5k  (9.5)
9 Morph  (9.5)
10 Libertongo  (9.5)
Top Groups
1 Performers  (9.3)
2 Booze Design  (9.3)
3 Oxyron  (9.3)
4 Censor Design  (9.3)
5 Triad  (9.3)
Top Coders
1 Axis  (9.8)
2 Graham  (9.8)
3 Lft  (9.8)
4 Crossbow  (9.8)
5 HCL  (9.8)

Home - Disclaimer
Copyright © No Name 2001-2024
Page generated in: 0.06 sec.