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-02-04 08:42
Ninja

Registered: Jan 2002
Posts: 411
Jack: There is no definitive way to store away registers in the beginning of an interrupt. Depending on the routines, I use this or that option, sometimes another one...

And LOL about the 'HCL-classic' :D I have to admit I prefer to use the 'Crossbow classic', who uses the accumulator to work with 8-bit values ;)
2009-02-04 08:47
Oswald

Registered: Apr 2002
Posts: 5094
JA: been using that "classic" and not knowing HCL exists.

Bregelad: I dont see the irq vector re-routing in the vblank. The X coord bug must come from the main prg, or bad d010 handling. you can save time by setting less sprite attributes, sprite pointer/x/y/color is enough for a general case.
2009-02-04 10:46
Bregalad
Account closed

Registered: Jul 2008
Posts: 42
Quote:
You should limit the IRQs to something like every 8th rasterline. That way you have enough time to finish the IRQ before the next one will start and avoid a lot of problems. And yes, the C64 is very slow :)

How I am supposed to do that ? AND the IRQ line with #$f8 or something that way ? Would that remove bugs ?
@Jack asser : This is really awesome, I did all those mod to my programm so that it is faster.
@Oswald : You don't see the IRQ being changed to sprite IRQ because this is done inside the "SpriteMultiplexer" routine.

I guess the bugs could be the main programm but I doubt that, the 8-sprite version of it is working fine, and the main programm is identical (exept it writes to arrays instead of registers). Even if I restrict the number of stars to 8 so that the programm is exactly the same as before I still get bugs.
I tried to write to registers in many orders but it doesn't make any differences. Should be my $d010 handling, but I double checked it and it seems ok.

Also how many scanlines am I supposed to set my IRQ before the sprite ? I guess 3 is the bare minimum, but in the worst case where I have to rewrinte all 8 sprites on the same line, it would need about 16-24 scanlines before so that I have time to rewrite all 8 ! This sounds like an enormous amount. Having a big margin like that may remove some bugs when many sprites are on the same line, but add other bugs as sprites are much more likely to overlap and to be rejected as there is more than 8 on a line.

When it comes to rewrite less flags, I don't know... If it doesn't allow to set all flags individually for each sprite, it's not a true general multiplexer. Almost all multiplexer examples I've seen does not allow Y-expanding for example. On the other hand I've just figured that those IRQ really needs to be fast, so I don't know.

The latest version so far...
SpriteIRQ
	inc $d019
	sta _areg+1.w
	stx _xreg+1.w
	sty _yreg+1.w

	ldx SpriteRasterIndex
_loop
	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
	lda SpritePosXL.w,X
	sta $d000,Y
	lda SpriteSortedPosY.w,X
	sta $d001,Y
	lda D010Buffer.w,X
	sta $d010
	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
-	inx
	lda InterruptLine,X
	beq -			;If raster line is 0, we should ignore it
	sta $d012
	cmp #$ff
	beq _lastInt		;If value is $ff, then it's the last interrupt of the frame
	sbc #$02		;If a new interrupt should occur in less than 3 scanlines
	cmp $d012		;Do it straight away
	bcc _loop
	stx SpriteRasterIndex	;Copy valid index and rasterline
	bcs +

_lastInt
	lda #<IRQ
	sta $fffe
;	lda #>IRQ
;	sta $ffff
+
_areg	lda #$00
_xreg	ldx #$00
_yreg	ldy #$00
	rti
2009-02-04 11:09
Bregalad
Account closed

Registered: Jul 2008
Posts: 42
Oh my I found the X position bug and it is *SOOOO* stupid.
In my IRQ I put "lda SpritePosXL.w,X" instad of "lda SpriteSortedPosXL.w,X", and that was causing all the mess. Now it works perfectly.
2009-02-04 11:49
Ninja

Registered: Jan 2002
Posts: 411
Two minor hints:

1) This reduces the need to modify the code by hand (check with your assembler syntax):

if (>IRQ != >SpriteIRQ)
    lda #>IRQ
    sta $ffff
endif

2) If you abuse a preset carry, I usually write the following command like this (for your case):

    sbc #3-1

instead of sbc #2. So, I easily see which value I really want to use and that I might need to make adjustments if the code around this instruction changes...
2009-02-04 12:18
JackAsser

Registered: Jun 2002
Posts: 2014
Quote: Jack: There is no definitive way to store away registers in the beginning of an interrupt. Depending on the routines, I use this or that option, sometimes another one...

And LOL about the 'HCL-classic' :D I have to admit I prefer to use the 'Crossbow classic', who uses the accumulator to work with 8-bit values ;)


Offtopic: "And LOL about the 'HCL-classic' :D I have to admit I prefer to use the 'Crossbow classic', who uses the accumulator to work with 8-bit values ;)"

Please elaborate on the 'Crossbow classic' because for me the accumulator has always worked with 8-bit values... :)
2009-02-04 12:23
WVL

Registered: Mar 2002
Posts: 902
Quote: Offtopic: "And LOL about the 'HCL-classic' :D I have to admit I prefer to use the 'Crossbow classic', who uses the accumulator to work with 8-bit values ;)"

Please elaborate on the 'Crossbow classic' because for me the accumulator has always worked with 8-bit values... :)


He means everybody does it ;)
2009-02-04 12:42
doynax
Account closed

Registered: Oct 2004
Posts: 212
Quote:
Also how many scanlines am I supposed to set my IRQ before the sprite ? I guess 3 is the bare minimum, but in the worst case where I have to rewrinte all 8 sprites on the same line, it would need about 16-24 scanlines before so that I have time to rewrite all 8 ! This sounds like an enormous amount. Having a big margin like that may remove some bugs when many sprites are on the same line, but add other bugs as sprites are much more likely to overlap and to be rejected as there is more than 8 on a line.
Or you could look at the whole timing problem from a slightly different perspective. That is you might opt to program the sprites as early as possible rather than as late as possible, e.g. right after the previous shape has finished with the sprite channel you're attempting to reuse. That way there's no need to estimate raster timing at all, with the drawback that some sprite which would otherwise be displayed imperfectly simply won't show up at all.

As for speeding up the interrupt handler itself about the best you can do is to unroll it completely and keep a separate interrupt handler per-sprite. That way you can poke sprite values directly into LDA immediates and STA to absolute addresses instead of indexing anything. Whether or not the cycle savings are worth the space depends on your game and how tightly you'll want to pack the sprites, but I've found it a useful method.

Oh, and you might want to clear the decimal flag before doing any arithmetic in an interrupt handler. Or not. Just beware of the issue as it can lead to some nasty bugs if you're not careful.
2009-02-04 14:24
Graham
Account closed

Registered: Dec 2002
Posts: 990
Nobody uses the decimal mode so no need to clear the decimal flag.
2009-02-04 14:47
doynax
Account closed

Registered: Oct 2004
Posts: 212
Quote: Nobody uses the decimal mode so no need to clear the decimal flag.


What.. No one has figured out a way to save cycles by using BCD arithmetic in a bithack?

Anyway, I managed to get bitten by this myself a while back.
Once in a blue moon my game would glitch for no apparent reason. Eventually it turned out (after *many* hours of debugging) to be caused by an interrupt being triggered during the dozen or so cycles it took to update the player's score counter. Making things worse was the fact that the collision detection logic would normally have finished running long before the visible display area, so it only ever happened during the the busiest screens.
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
megasoftargentina
BYB/Hokuto Force
DKT/Samar/sidDivers
Murphy/Exceed
t0m3000/hf^boom!^ibx
LightSide
Raf/Vulture Design
zscs
Guests online: 104
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 Webmasters
1 Slaygon  (9.6)
2 Perff  (9.6)
3 Sabbi  (9.5)
4 Morpheus  (9.4)
5 CreaMD  (9.1)

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