| |
Oswald
Registered: Apr 2002 Posts: 5094 |
the holy gray of HW scroll: how to avoid spr pointers becoming visible
Hi!
Lately playing with game coding ideas fascinated me. However scrolling games are hitting the wall of the evil non-bufferable $d800, not to talk about the time needed to copy around scr ram even when buffered. I have thought up ways to divide the scr ram copy into several frames, but $d800 must be moved in one frame no matter what.actually it takes about 126 rasterlines to move all the $d800 data, even using a speedcode!
full hw scrolling is nice, and char bullets are even nicer (ie: I'd like to have char mode for my theoretical game). but this is where something horrible happens: the sprite pointers will become visible, and unless we accept the 8 char wide bug on the screen I see no way around.
or is there ?
I heard there's something tricky going on in WVL's PD to circumvent this. Jack, WVL, whats that ? I'm afraid not something usable in a freescrolling game.
the closest I came is to build a screen with stretching a full char row down in bitmap mode, and shuffling around VIC's scrram pointers to get the colors working. this is the best one I could come up with, but the memory layout and the code is messy (multiplex sprites on that baby, and where are my char bullets?)and needs a lot of mem.
sorry this became quite lengthy :) waiting for suggestions.
|
|
| |
WVL
Registered: Mar 2002 Posts: 902 |
Hey Ossie,
why didnt you ask on IRC? :)
Nothing tricky going on. I have fixed sprite pointers, and adjusted the bitmap (and sprite pointers) to make everything work out.. simple as that. (like, when i needed red+pink+blue, i'd chose $2a,$a2,$62,$6a,$26 or $a6 for spritepointer..)
AFAIK, there's no holy grail :( except only using $d800 colors, which nullifies the use of bitmap. I wonder how Fred's Back is doing it?
Oh.. about $d800 copying, I only have to copy one single line each frame and never a full screen.
How does it w0k?
Imagine you have a fixed screen, and you're starting to scroll up. everythings fine. Now, line 26 starts with data that is located at $1f40 in the bitmap, and there's only $c0 bytes left there, ie, not a full line.
So at that point i do a $dd00/$d018 switch and jump to the next bitmap. Now, this one starts at $1f40, ($c0) bytes and then continues from $0000.
When bitmap 2 hits the top of the screen, I have to stop linecrunching and I switch to first bitmap = bitmap 2. But suddenly my $c0 offset disappears! So I correct for that with DMA-delay.
That's all there's to it.
So i use :
- offsetted bitmaps (or rather one continuous bitmap, depending how you look at it :D)
- whenever I need to start the screen with one of the offsetted bitmaps, I need to dma-delay the screen to scroll it sideways aswell.
BTW, i think if you're only scrolling vertical, you can keep going on like this (i think) without ever having to copy a full $d800 screen and only single lines.. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
"why didnt you ask on IRC? :)"
well, checking... hmm... wvl is not online ;)
thx for the explanation, someone rumoured something like you revsp the screen in place or sth like that, so I thought you have something ;) |
| |
Cruzer
Registered: Dec 2001 Posts: 1048 |
I bet Fred's Back has blue sky where there's spr-pnts. Since it's bitmap, the gfx just needs to be cleared, then the spr-pnts don't matter. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
the problem is char bullets here, to compensate the opposite should be as fred's back: spr pointers should be enclosed in platforms and stuff (instead of making them 'sky'), so soft bullets cant run on them... this is the easyest solution, but its hard to imagine how good levels can be designed around this. |
| |
pernod Account closed
Registered: Nov 2004 Posts: 25 |
Maybe my memory is a bit rusty, but I think Exilon/Hz showed me a trick he used for a game (unfinished, of course) around 1990. He used some timer interrupt trick, like setting d018 before every badline, then setting it back before the sprite fetches in the right area of the screen. It is only possible to use six sprites per raster line though.
|
| |
WVL
Registered: Mar 2002 Posts: 902 |
Quote: Maybe my memory is a bit rusty, but I think Exilon/Hz showed me a trick he used for a game (unfinished, of course) around 1990. He used some timer interrupt trick, like setting d018 before every badline, then setting it back before the sprite fetches in the right area of the screen. It is only possible to use six sprites per raster line though.
brrrrr that sounds really nasty... i guess it works, but wouldnt call it the holy grail :) |
| |
pernod Account closed
Registered: Nov 2004 Posts: 25 |
Quote: brrrrr that sounds really nasty... i guess it works, but wouldnt call it the holy grail :)
Come on, don't be a wuzz! This is where macho coding begins. ;-)
|
| |
Burglar
Registered: Dec 2004 Posts: 1101 |
if there is no holy grail, maybe a fixed $d800 color for the whole screen would work, you lose a color per char, but you gain loads of rastertime. if you use a medium color, good graphicians will know how to use it and make stuff look pretty anyway. dunno how that would affect char-bullets though. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
working the levels around the spr pointers seems to be better :) |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: if there is no holy grail, maybe a fixed $d800 color for the whole screen would work, you lose a color per char, but you gain loads of rastertime. if you use a medium color, good graphicians will know how to use it and make stuff look pretty anyway. dunno how that would affect char-bullets though.
<Post edited by JackAsser on 3/10-2007 20:10>
"...I'd like to have char mode..."
Fixed $d800 in char-mode => fixed 4 colors always.
Sprite-pointers are a LOT worse to handle in char mode since the gfx also changes.
Another thing, "revsp" is not possible. VSP happens when you go from idle state to badline state too early. badline to badline == FLI and will not VSP. I.e. to "revsp" you will need one raster line with idle-state graphics.
Sorry for not adding any solutions to your problem Ossie. Just wanted to shed lights on a few things regarding this.
To be a bit off-topic: I played with FLI-VSP yesterday and came to the conclusion that you can't VSP a FULL FLI image (with all 200 lines visible simultaneous). I.e. all 200 lines can't be FLI. IMO the first and last line will be corrupt (198 lines in total). Any one who can prove any different?
I can perhaps see someone like crossbow manage 199 lines, but not 200 imo. Not without cheating the last bad-line.
=D
|
| |
Hein
Registered: Apr 2004 Posts: 954 |
24 chars is not an option here? (I know, that is for sensitive people only, but a game is about playability first.) |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: 24 chars is not an option here? (I know, that is for sensitive people only, but a game is about playability first.)
@Hein: If you refer to my (as I said) off-topic post about 200 lines of VSPing FLI I just asked out of curiosity, certainly not for a game. ;D
Now, if you refer to Oswalds original question 24 chars doesn't solve anything etc. |
| |
Hein
Registered: Apr 2004 Posts: 954 |
ah, right.. I thought it was VSP only. |
| |
Radiant
Registered: Sep 2004 Posts: 639 |
A trick to reduce the $d800 work is to only change colours every second (or third, fourth etc) column. Then you only have to $d800-scroll the columns where the changes take place. |
| |
Fungus
Registered: Sep 2002 Posts: 686 |
If your planning to scroll the screen at a fixed rate, why bother with dma scrolling? Seems you can just do as you say and split the scroll up into several frames. I can understand the color memory being a problem, but like Burgie suggested why not set it to a static color. If it's a space shoot em up, just set it to black, etc... ?
|
| |
Radiant
Registered: Sep 2004 Posts: 639 |
(Applies for rows when scrolling vertically, of course...) |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
the evil of the d800 that you can not split the copying of it into several frames, so it doesnt matter how clever you are d800 has to be done in one frame, and as a game should be opted for worst case scenario, this will limit the speed.
I have 'decided' to design the levels around the sprite pointers (remember char bullet problem), as it gives me full d800 freedom, and no more screen shifting around -> there's 2x the time to do stuff compared to any other freedir scrolling games.
dont forget tho, that so far this is just a theoretical thinking about how a game in 2007 could be done better than anything so far :) |
| |
pernod Account closed
Registered: Nov 2004 Posts: 25 |
It is possible to split the d800-copying into two frames in stead of one.
The first frame you copy the upper half of the d800 area. Start doing this around rasterline 100. The next frame you copy the lower half. Also start this on rasterline 100 or so. Do the copying row by row starting with the uppermost line. That way the copying will never interfer with VIC.
|
| |
Hein
Registered: Apr 2004 Posts: 954 |
<Post edited by Hein on 4/10-2007 10:21>
oh, but my theoretical game is always 1% better than yours. ;) |
| |
johncl
Registered: Aug 2007 Posts: 37 |
As pernod says, the copy can be split up somewhat. But I guess the biggest problem with this is that your copy can still take too much raster time making it e.g. hard to do a sprite multiplexer (unless you interleave that code with the copy which certainly is possible). |
| |
Radiant
Registered: Sep 2004 Posts: 639 |
johncl: Or just multiplex using interrupts? :-) |
| |
pernod Account closed
Registered: Nov 2004 Posts: 25 |
Quote: As pernod says, the copy can be split up somewhat. But I guess the biggest problem with this is that your copy can still take too much raster time making it e.g. hard to do a sprite multiplexer (unless you interleave that code with the copy which certainly is possible).
Yes, it would take around 80 lines. I would do this in the background, and the multiplexer with raster irqs.
|
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
<Post edited by Oswald on 4/10-2007 11:31>
lda d800,y
sta d800,x = 9 cycles *1000=9000 / 63 = 142 lines.
they way of splitting you advise doesnt helps on the speed, as it just moves the place of the operation to be across 2 frames. it's only good to avoid frame update bugs. ;)
as you see for a freedir fullscr game there's only 170 lines are left for whatever a game wants to do per frame. (spritesort,multiplex, etc etc)
counting with a worst case scenario 32 sprites multiplexed would take about another 60-100 lines away. you are left with ~ 100 lines for char bullets drawing, collision checks, movement logics, spawning enemies, etc.
(and now this will be what color? ;) )
and another edit: doing the d800 copy while the screen is displayed is pretty nifty though, allows software bullets to be done outside the visible screen ;) |
| |
johncl
Registered: Aug 2007 Posts: 37 |
Quote: Yes, it would take around 80 lines. I would do this in the background, and the multiplexer with raster irqs.
Ah well, I do all my code in the raster irqs and using the good old border color trick to measure the time used and see all the time what I have available. Atm I would get in trouble with sprite multiplexing if I needed more than 3 levels in my little scroller (but its easy for me to split up the copy to insert some sprite multiplexing code if needed). But I am quite sure my game could be immensely improved in that sense since this is my first go at making a 100% asm game on the C64. :)
Atm I am wondering what the best way is to set up the sprite multiplexing, or general reuse of the available sprites as they enter and leave the screen. I might have to maintain a list of "mobs" per column so I know where they left the screen the last time and easy check on when they should reappear. But that might be wasting a lot of memory with "empty spots". |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
indeed, it's annoying in fex. turrican that you can kill enemies by having them go offscreen ;) how about having a list of all enemies with x/y coords, and notoriously checking the list wether some of them came onscreen, then setting the ones going offscreen back to inactive state. you can also divide all these computation amongst several frames, so full list check is only done every 4 frame or so. |
| |
WVL
Registered: Mar 2002 Posts: 902 |
<Post edited by WVL on 4/10-2007 13:34>
Maybe a different idea.
-dynamic charset.
You just have your agsp screen, and sprite multiplexer.
Now, what you do is that you check what the value of the spritepointers will be at the rasterlines where $07f8-$07ff is displayed. And now (here comes the dynamic part), you change the charset so the correct charshapes are displayed.
This doesnt give you total freedom though.. f.e. for optimal flexibility you need to have all sprite pointers a different value.
Maybe it's a good idea to make _all_ chars in the problematic charrow unique. Say #$00-#$27.
Now, if your sprite pointers are always in the #$00-#$27 range, you can make sure you can display everything correctly.
Ofcourse at a cost.. You need to copy 40*8 bytes every frame = 320 bytes. But still less than copying the screen around.
Maybe this works for you? Or else I'd go with Pernod's idea, you only need fixed timing in 8 rasterlines..(too bad about the 6 sprite limit (is this really so? I'd guess you have exactly 1 cycle left in a badline in the correct position, and plenty of cycles left in the other lines?)
urgh. Stupid me : you only need to have fixed timing in the badline (and maybe the line before too, when the sprite data is being fetched), then quickly set 07f8 to stay at the spritepointers.. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
great idea, but messy to realize :/ I'd restrict chars to 00-7f and sprites to 80-ff (or some other tradeoff), then there would be no need for the extra irq and rewrite of 40 chars, instead we loose a lot of gfx space :) a problem you havent adressed here: now we need to temp what chars 7f8-800 should have. -> extra mess around in the char bullet code :/ |
| |
doynax Account closed
Registered: Oct 2004 Posts: 212 |
WVL:
Switching between charsets at the very beginning and end of a char-row should be easy enough. But you'd be in trouble if two sprites happened to share the same frame, plus the you'd waste almost a full 2k in the VIC bank for the extra charset.
I figure it'd be easier just to reserve eight fixed sprites and switch charsets (to one with new sprite pointers) instead. You'd probably want an extra charset for double buffering anyway, and updating the visible portion of the sprites (max 192 bytes) is probably still faster and easier than juggling the unique chars.
Also it'd probably be a good idea to tweak the multiplexer to disallow having to deal with more than eight sprites in that row.
I shudder to think of having to deal with sprites disappearing into the upper border when doing VSP/linecrunch. |
| |
WVL
Registered: Mar 2002 Posts: 902 |
Quote: great idea, but messy to realize :/ I'd restrict chars to 00-7f and sprites to 80-ff (or some other tradeoff), then there would be no need for the extra irq and rewrite of 40 chars, instead we loose a lot of gfx space :) a problem you havent adressed here: now we need to temp what chars 7f8-800 should have. -> extra mess around in the char bullet code :/
<Post edited by WVL on 4/10-2007 14:27>
Hey! it's a solution ;) It ain't perfect :D But neither is Pernod's idea, or working around the problem by level-design. :)
that's life :D
Quote:I shudder to think of having to deal with sprites disappearing into the upper border when doing VSP/linecrunch. That's nasty, yeah. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
I'm starting to leaning against that the traditional way presents less problems :) maybe if the living shit is optimised out of it, it can do some miracles :) |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
"I shudder to think of having to deal with sprites disappearing into the upper border when doing VSP/linecrunch."
That is not as nasty as one might think since all timing required is outside/before the sprite fetches. One thing though, when line-crunching sprite 0 interferes with the $d011 write so, in that area you may only use sprites 1-8.
In practice it's like any AGSP but instead of wasting cycles each line you do some $dc04 thingies to get it right. |
| |
pernod Account closed
Registered: Nov 2004 Posts: 25 |
Like Jackie says, sprite zero becomes unusable because of the linecrunching. Then later, on one single line, you can't use sprite 1 either (I'm referring to the d018-trick I wrote about). But probably the multiplexer can take care of that, if it's altered a bit.
It only takes about 30 cycles to do the d018-interrupt-thing.
|
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: Like Jackie says, sprite zero becomes unusable because of the linecrunching. Then later, on one single line, you can't use sprite 1 either (I'm referring to the d018-trick I wrote about). But probably the multiplexer can take care of that, if it's altered a bit.
It only takes about 30 cycles to do the d018-interrupt-thing.
Yeah, and I meant of course that only sprites 1-7 are available (not 1-8!, only crossbow and graham have 9 sprites!)
|
| |
cadaver
Registered: Feb 2002 Posts: 1160 |
Another idea: since there is no time wasted on screen copying, what about letting the sprite pointers stay fixed (for example $f8-$ff) and copying sprite & char data as necessary (possibly realtime-depack & flip sprites for more animations possible, MW4 already does this for all bullet/item sprites while also doing unaccelerated scrolling :))
Of course for multiplexed sprites, you'd need for example double or triple the chars.
Btw. there's one more downside to AGSP: it's either the status panel made with sprites and no smooth fading of sprites from the top screen edge, or no panel... |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
<Post edited by Oswald on 4/10-2007 19:28>
hmmm,
(edit, will be this one green too?:)
how about using a temp screen with pointers f8-ff and having 2 nmis to switch to the temp screen at the critical char row? benefits: sprite multiplexing can go the traditional way, also char bullets can go on without caring whatever is at 7f8-7ff.
edit: ok, the above needs some more thoughts, btw the vic reads the char pointers only once, this can be extremely useful! now thinking on it some more :) |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
is it possible to change screen _after_ sprite pointers been read in but _before_ vic fetches char pointers ? :) => split the char and sprite pointers between 2 screens, switch to correct chars screen after spr pointers been readed and before vic reads char data. switch back afterwards. this would rule. :) |
| |
Burglar
Registered: Dec 2004 Posts: 1101 |
it might be wise to already make a memorymap (as thats based on hard restrictions) and requirements specification. I'll leave the memorymap to the less crappy coders than me ;)
but I'll have a go with the requirements:
- 50 fps
- (near) fullscreen playfield
- scrolling in x+y directions
- max scrollspeed: 4 pixels (?)
- charmode with dynamic $d800 color
- 32 multiplexed and animated sprites
- char bullets
- ingame music + sfx (?)
- onscreen player scores (?)
putting up requirements usually helps a lot to brainstorm, as you know what you want.
anyway, please correct me if I'm wrong with any of the requirements, and if there need to be more.
now, the coding topics are getting a bit beyond my rusty skills, so no need to bore you with obvious nonworking suggestions ;) but keep it up! ;) |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
you are right with the requirements. agsp would make 8pixels / frame scrolling or more possible tho :) btw sprite 0 is unavailable for the whole agsp area ? |
| |
Frantic
Registered: Mar 2003 Posts: 1648 |
A somewhat related article on codebase:
http://codebase64.org/doku.php?id=base:multidirectional_scrolli.. |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: is it possible to change screen _after_ sprite pointers been read in but _before_ vic fetches char pointers ? :) => split the char and sprite pointers between 2 screens, switch to correct chars screen after spr pointers been readed and before vic reads char data. switch back afterwards. this would rule. :)
Seriously Oswald... Implementing my bro's trick is not that difficult at all and will give you most bang for the bucks imo. It's just at ONE raster line (the one just before the sprite-pointer bugs) you have to be tricky on. On that particular line you may only have 6 sprites but that's it. Also, around this line you will need to switch $dd00/$d018 anyways because of linecrunching so the extra job needed is quite small...
Also the splitting of the $d800 across two frames is not just a delay of the $d800 copy, it actually gives you raster time free in the middle of the two copies. Of course in the end it's just as much copy as usual, BUT you gain quite alot of raster time in between those copies so that in reality you can treat it as worst case being half of what u said before. |
| |
WVL
Registered: Mar 2002 Posts: 902 |
Quote: Seriously Oswald... Implementing my bro's trick is not that difficult at all and will give you most bang for the bucks imo. It's just at ONE raster line (the one just before the sprite-pointer bugs) you have to be tricky on. On that particular line you may only have 6 sprites but that's it. Also, around this line you will need to switch $dd00/$d018 anyways because of linecrunching so the extra job needed is quite small...
Also the splitting of the $d800 across two frames is not just a delay of the $d800 copy, it actually gives you raster time free in the middle of the two copies. Of course in the end it's just as much copy as usual, BUT you gain quite alot of raster time in between those copies so that in reality you can treat it as worst case being half of what u said before.
<Post edited by WVL on 5/10-2007 09:38>
I have to agree with jackie here..
but if you use AGSP, there's no need to ever copy a full $d800 screen IMO. (except when you've only implemented a linecruncher or only dma-delay. You need both to avoid $d800 copying) |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: I have to agree with jackie here..
but if you use AGSP, there's no need to ever copy a full $d800 screen IMO. (except when you've only implemented a linecruncher or only dma-delay. You need both to avoid $d800 copying)
When the VSP wraps from 39 -> 0 you may decrease the linecruncher by one row to avoid $d800 copy.
When the VSP wraps from 0 -> 39 you may increate the linecruncher by one row to avoid $d800 copy.
However, when the linecruncher wraps due to a VSP-adjust I think you still must copy the $d800 area or maybe not... Feels that there must be some case when you actually need to copy but perhaps not. ;D Must do a test-implementation tonight or so. ;D |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
looking at the vic article timing diagrams, it seems like you can have up to 3 cycles (RMW) on a bad-line with 8 sprites on, and those cycles happen exactly when I need them to (afer sprite reads, before charptr fetches) are you sure only 6 sprites is possible ? with an nmi interrupt, and nmi timers to stable things this -in theory- is possible.
https://sh.scs-trc.net/vic/vic_article_3.6.htm
|
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: looking at the vic article timing diagrams, it seems like you can have up to 3 cycles (RMW) on a bad-line with 8 sprites on, and those cycles happen exactly when I need them to (afer sprite reads, before charptr fetches) are you sure only 6 sprites is possible ? with an nmi interrupt, and nmi timers to stable things this -in theory- is possible.
https://sh.scs-trc.net/vic/vic_article_3.6.htm
First you need to switch in the correct gfx after the sprite fetches, exactly as u say. Then you must wait until the DMA has fetched the 40 correct chars, then you must switch in the correct sprite pointers again. Thus you need to switch twice.
Thus you may use the 2 RMW cycles available for the first switch, but then you need to lda+sta/inc/dec directly after (6 cycles). You have 3, but u need 3 more. Bye bye with two sprites, #0 and #1.
Also, due to sprites over linecrunch area sprite #0 is a no no anyways, at least "up there".
|
| |
pernod Account closed
Registered: Nov 2004 Posts: 25 |
Quote: looking at the vic article timing diagrams, it seems like you can have up to 3 cycles (RMW) on a bad-line with 8 sprites on, and those cycles happen exactly when I need them to (afer sprite reads, before charptr fetches) are you sure only 6 sprites is possible ? with an nmi interrupt, and nmi timers to stable things this -in theory- is possible.
https://sh.scs-trc.net/vic/vic_article_3.6.htm
No, I am not sure how many sprites that are possible on that line, but the best I could remember was six. Please come back and tell me when you've tried it out! ;-)
|
| |
pernod Account closed
Registered: Nov 2004 Posts: 25 |
Quote: First you need to switch in the correct gfx after the sprite fetches, exactly as u say. Then you must wait until the DMA has fetched the 40 correct chars, then you must switch in the correct sprite pointers again. Thus you need to switch twice.
Thus you may use the 2 RMW cycles available for the first switch, but then you need to lda+sta/inc/dec directly after (6 cycles). You have 3, but u need 3 more. Bye bye with two sprites, #0 and #1.
Also, due to sprites over linecrunch area sprite #0 is a no no anyways, at least "up there".
It would be nice to have a multiplexer that can display eight sprites per line, seven at the top and six(?) where the sprite pointers are visible. My gut feeling says it's only a small modification to a sorting routine.
|
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: It would be nice to have a multiplexer that can display eight sprites per line, seven at the top and six(?) where the sprite pointers are visible. My gut feeling says it's only a small modification to a sorting routine.
Hmmm, now that I think of it MAYBE 7 sprites are possible. Must do an experiment to verify the idea though. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
<Post edited by Oswald on 5/10-2007 11:10>
jack, preload a register, then do RMW, then write register. one sprite is crippled for one rasterline -> acceptable, you cant have everything :)
you must have 1 cycle even without RMW on a badline+8sprites. |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: jack, preload a register, then do RMW, then write register. one sprite is crippled for one rasterline -> acceptable, you cant have everything :)
you must have 1 cycle even without RMW on a badline+8sprites.
<Post edited by JackAsser on 5/10-2007 11:28>
All sprites will be crippled. You need to reset the sprite pointers directly after the char fetch. Problem is that you only have RMW-cycles there hence you won't be able to fit your STA with the preloaded value there. If you remove sprite #0 you'll have 2 normal cycles there though, exactly enough for an RMW-write operation to fit if started just before the char fetch. Now, the problem is that u've already used that when u made the first switch. This means you have to remove yet another sprite. Now you've freed up 4 cycles and have 3 RMW-cycles. It's enough for an LDA+STA.
Although, maybe you can use the 2 freed up cycles from the first sprite to the the sta actually. If the sta-opcode is RRWW it'll fit nicly. If it's RRRW though u're fucked though since the last read-access will hit the RMW-cycle => Cpu stalled. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
well, but still this will only happen when 8 sprites on a row on that particular line. I think I can live with that :D |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: well, but still this will only happen when 8 sprites on a row on that particular line. I think I can live with that :D
<Post edited by JackAsser on 5/10-2007 11:45>
Hehe yeah ok. Another problem though. Imagine this sprite-pointer row is the very first row visible. Perhaps only half-visible, that means you have to this $d018 trick in the linecrunch/vsp area... Good luck with that. I'm sure it's possible but it'll be über-messy. :D
To avoid it you could perhaps limit the line cruncher to only crunch 24 rows, thus the sprite-pointer row will never be the first. Doing this however will remove the possibility of a non-copy-d800 solution since on that wrap you'll be forced to copy the graphics.
Hmm... actually perhaps not so messy after all. Simply have the correct screen on before the VSP and after the VSP enable the screen with the correct sprite pointers. Perhaps u get some sprite glitches but it's OK I think. This you may always do in fact. |
| |
WVL
Registered: Mar 2002 Posts: 902 |
Quote: Hehe yeah ok. Another problem though. Imagine this sprite-pointer row is the very first row visible. Perhaps only half-visible, that means you have to this $d018 trick in the linecrunch/vsp area... Good luck with that. I'm sure it's possible but it'll be über-messy. :D
To avoid it you could perhaps limit the line cruncher to only crunch 24 rows, thus the sprite-pointer row will never be the first. Doing this however will remove the possibility of a non-copy-d800 solution since on that wrap you'll be forced to copy the graphics.
Hmm... actually perhaps not so messy after all. Simply have the correct screen on before the VSP and after the VSP enable the screen with the correct sprite pointers. Perhaps u get some sprite glitches but it's OK I think. This you may always do in fact.
He. Maybe i have to implement this in PD aswell :D I only have max 3 sprites over the $7f8 area anyway :)
Would solve a lot of problems. Now, if only i could remember which sprites I made to hold the ball ;) (but that was given by the colors of the bitmap anyway ;P)
|
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
<Post edited by Oswald on 5/10-2007 12:16>
its enough to have 24 linecrunched rows, as linecrunching 25 lines equals to not crunching at all.
(this red&green stuff seriously sucks)
|
| |
Krill
Registered: Apr 2002 Posts: 2980 |
Quote: All sprites will be crippled. You need to reset the sprite pointers directly after the char fetch. Problem is that you only have RMW-cycles there hence you won't be able to fit your STA with the preloaded value there. If you remove sprite #0 you'll have 2 normal cycles there though, exactly enough for an RMW-write operation to fit if started just before the char fetch. Now, the problem is that u've already used that when u made the first switch. This means you have to remove yet another sprite. Now you've freed up 4 cycles and have 3 RMW-cycles. It's enough for an LDA+STA.
Although, maybe you can use the 2 freed up cycles from the first sprite to the the sta actually. If the sta-opcode is RRWW it'll fit nicly. If it's RRRW though u're fucked though since the last read-access will hit the RMW-cycle => Cpu stalled.
STA abs should be RRRW. At least that's what seems logical (and is supported by a quick peek into the VICE sourcecode): read 1 opcode byte and 2 argument bytes, then write byte to memory. Also, STA $d020 etc. does not produce a grey dot one cycle before actually changing the colour, which is the case with RMW instructions. Plus, RRWW would mean you could use STA for opening the sideborders with all sprites enabled, which in fact only works with RMW instructions.
So it really seems like only 6 sprites there. |
| |
doynax Account closed
Registered: Oct 2004 Posts: 212 |
Quote: STA abs should be RRRW. At least that's what seems logical (and is supported by a quick peek into the VICE sourcecode): read 1 opcode byte and 2 argument bytes, then write byte to memory. Also, STA $d020 etc. does not produce a grey dot one cycle before actually changing the colour, which is the case with RMW instructions. Plus, RRWW would mean you could use STA for opening the sideborders with all sprites enabled, which in fact only works with RMW instructions.
So it really seems like only 6 sprites there.
You mean there's a way to avoid those annoying gray dots I sometimes see on my C128? Details please :) |
| |
WVL
Registered: Mar 2002 Posts: 902 |
you always get grey dots. Krill was talking about which cycle (write-cycle) produces the dot as a proof that STA is RRRW and not RRWW (which it can't be as 6502 needs to read 3 bytes).. |
| |
Krill
Registered: Apr 2002 Posts: 2980 |
Yes, i was talking of one extra grey dot. STA/X/Y produce one grey dot when switching colours (new VIC-II, that is) while RMW instructions produce two grey dots due to two write cycles: the first writes the unaltered value back, the second writes the altered value. Hence you first get a grey dot but the colour stays the same for one cycle, and then you get another grey dot and the changed colour. |
| |
doynax Account closed
Registered: Oct 2004 Posts: 212 |
Damn.. I guess I'll just have to live with them then :( |
| |
Krill
Registered: Apr 2002 Posts: 2980 |
Where do you have them? They never bothered me except with split rasterbars :) |
| |
doynax Account closed
Registered: Oct 2004 Posts: 212 |
Quote: Where do you have them? They never bothered me except with split rasterbars :)
I seem to recall having three of them in the scoreboard split. Can't say for sure as I don't have monitor at the moment (I'm not paying those public service fuckers just so I can use my TV as a monitor..).
Anyway I guess I'm just a bit of a perfectionist, I would never have noticed it in anyone else's production but it bugs the hell out of me to see them in my own. I'm also frustrated by not being able to deal with restore in a satisfactory manner either for that matter. |
| |
chatGPZ
Registered: Dec 2001 Posts: 11386 |
Quote:
I'm also frustrated by not being able to deal with restore in a satisfactory manner either for that matter.
why is that? checking if an nmi comes from restore or somewhere else is easy enough, whats the problem? |
| |
doynax Account closed
Registered: Oct 2004 Posts: 212 |
Quote: Quote:
I'm also frustrated by not being able to deal with restore in a satisfactory manner either for that matter.
why is that? checking if an nmi comes from restore or somewhere else is easy enough, whats the problem?
My funky charmode thingie triggers an timer NMI interrupt once every five scanlines or so (every four scanlines in a 16-pixel char actually, except on the first line), and each interrupt takes somewhere between 12-18 cycles.
There's just no way I'm sticking a restore test in there. |
| |
chatGPZ
Registered: Dec 2001 Posts: 11386 |
ah ok, i see the problem... what i have done in a similar situation before was resyncing the timer to the raster somewhere else (in border or whatever), so hitting restore will still trigger an unwanted nmi, and disturb the timer driven routine, but it will go into sync again with at most one frame delay, so its not terribly critical. |
| |
doynax Account closed
Registered: Oct 2004 Posts: 212 |
Quote: ah ok, i see the problem... what i have done in a similar situation before was resyncing the timer to the raster somewhere else (in border or whatever), so hitting restore will still trigger an unwanted nmi, and disturb the timer driven routine, but it will go into sync again with at most one frame delay, so its not terribly critical.
No, but it doesn't look very professional either :(
And even then it took some doing to support it ($00/$01 needs to be executable). Life would've been so much easier if the Commodore engineers had just decided to trigger a reset instead, though to be fair they could hardly have been expected to predict this kind of hardware abuse. |
| |
chatGPZ
Registered: Dec 2001 Posts: 11386 |
Quote:
No, but it doesn't look very professional either :(
still a lot better than having to restart the entire game when you accidently hit restore :) |
| |
Cybernator
Registered: Jun 2002 Posts: 154 |
Quote: My funky charmode thingie triggers an timer NMI interrupt once every five scanlines or so (every four scanlines in a 16-pixel char actually, except on the first line), and each interrupt takes somewhere between 12-18 cycles.
There's just no way I'm sticking a restore test in there.
Is there no way for you to use IRQ instead, and leave NMI in unacknowledged state? |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
irq is used to plex sprites, while nmi does the vic tricks. anyway disabling restore is absolutely not needed, its just like you want to disable the reset button on a pc. if the user presses it --> he wanted it. it was 15-20 years ago when being able to disable runstop or restore made you the cool kid of the block imho. ;) its not like being able to feed the addy of an rti into 2 memory vectors or never acknowledging an nmi is a huge achievment... |
| |
Fungus
Registered: Sep 2002 Posts: 686 |
Oswald, as I was mentioning on IRC, you can go ahead and have part of the game running in real time loop (outside IRQ) , this would be say... you $d800 moving. Keep a switch to say "Move colors now?" and you modify this switch from inside the IRQ. In this way you can have the routine synced to frame. Yet, it is not inside any IRQ, so you can go ahead an multiplexer or whatever over the top of it. You can either have it wait, or just skip the routine if you want to do some calculations real time (enemy movement, AI, etc). This also makes it easier to have different routines for different enemies, seamless integration of different types of on screen action, and many many other things. Things like sprite animation do not need to be done every frame. Things like movement also do not need to be done every frame. You can also "interleave" routines easier this way and make the game seem like it is doing more than it actually is. Many commercial games are coded in this fashion. :)
These and many other reasons I am sure you can come up with, are why I mentioned this to you. I'm sure you can come up with many ways to use such a technique. (Game coding is not demo coding ;D )
|
| |
doynax Account closed
Registered: Oct 2004 Posts: 212 |
Quote: Oswald, as I was mentioning on IRC, you can go ahead and have part of the game running in real time loop (outside IRQ) , this would be say... you $d800 moving. Keep a switch to say "Move colors now?" and you modify this switch from inside the IRQ. In this way you can have the routine synced to frame. Yet, it is not inside any IRQ, so you can go ahead an multiplexer or whatever over the top of it. You can either have it wait, or just skip the routine if you want to do some calculations real time (enemy movement, AI, etc). This also makes it easier to have different routines for different enemies, seamless integration of different types of on screen action, and many many other things. Things like sprite animation do not need to be done every frame. Things like movement also do not need to be done every frame. You can also "interleave" routines easier this way and make the game seem like it is doing more than it actually is. Many commercial games are coded in this fashion. :)
These and many other reasons I am sure you can come up with, are why I mentioned this to you. I'm sure you can come up with many ways to use such a technique. (Game coding is not demo coding ;D )
I still need both IRQs and NMIs. IRQs are used for the multiplexer and NMIs to hack the charmode together. But beyond that I also run all the game logic from inside reentrant IRQs so I can do background tasks outside of them.
Right now the "main loop" as it were, in other words the code executing outside of any interrupt handlers, only increments a counter so I can measure the number of idle cycles. But it's my intention to eventually run background disk-streaming from there whenever the CPU isn't otherwise occupied. Note that you need a simple lock (a pair of INC/DEC instructions) to make sure you're not already in an update.
Actually if you wanted to you could run any number of tasks from within IRQs in this fashion. Preemptive multitasking. Sort of.. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
indeed, a game being able to properly frameskip while keeping the logical movement/spr anim speed constant would be nice. This introduces new problems which I should think about throughoutly I dont see a clear solution for them atmo. Fex. $d800 copy, or what if you have to move screen&d800 by more than 1 char steps. |