Sprites

Here you can ask questions or provide insights about how to use efficiently 6502 assembly code on the Oric.
User avatar
Iapetus
Flying Officer
Posts: 135
Joined: Thu Mar 19, 2009 10:47 pm

Sprites

Post by Iapetus »

Hi

What would be the most efficient way to way to plot 4 sprites (3x16 bytes)?

The sprites actually are 2x16 bytes but I will have them preshifted in memory so when painting the sprites I will paint one more byte for each of the 16 rows.

I will be using masks because the background must be preserved. What I am doing at the moment is:

- find location on screen
- save background
- AND mask
- OR sprite
Twitter: @newIapetus
Ko-fi:iapetusretrostuff
itch.io: Iapetus
Youtube: Iapetus Retro Stuff
User avatar
Dbug
Site Admin
Posts: 4437
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: Sprites

Post by Dbug »

Do you really need to save the background, can't you just have an off screen copy of the background?

Basically there are many many different ways of doing all that, and it mostly depends of parameters like the number of sprites, their size, the number of overlapping events, and the amount of memory you have.

If you can afford to have an off-screen buffer, you can do all the compositing there without fearing flickering and glitches and then update whole rectangles from the off-screen buffer to the real screen. (This allows some neat optimizations as well because you are not obliged to have 40 bytes large off-screen, you can use 32 bytes for example.)

Some other things to consider is how your inner loop looks like. Incrementing zero page pointers and then using zero page addressing to the screen is more costly than using absolute addressing, but it can make the code tricky. If your sprites are less than 6 scanlines high, you can address all of it from one single address (40*6=240) using an index register.

From a memory storage point of view, what would make sense is to have the mark and the sprite data very close or interleaved, so you can access them from one single pointer with just some index.

I remember that I at some point did experimentations where I stored the off-screen buffer vertically instead of horizontally (ie: incrementing the index register would access the next scanline instead of the next byte of the same scanline), this allows some nice optimization strategy, like in your case you could just set three absolute addresses (on the top of each column), and then just use one index register to access the scanlines. Endless possibilities :)
User avatar
Iapetus
Flying Officer
Posts: 135
Joined: Thu Mar 19, 2009 10:47 pm

Re: Sprites

Post by Iapetus »

At the moment my routine is not optimised, I just wanted to see if things were working. So I am adding 40 at every line to the low byte of the zp pointer and then add one to the high byte if carry is set but I knew this could done in another away, absolute addressing as you said.

Thank you for the hints on using a back-screen buffer rectangle, that is interesting, I just will have to figure out the best way to dump it to the real screen the fastest way possible. The play area takes only 3840 bytes.
Twitter: @newIapetus
Ko-fi:iapetusretrostuff
itch.io: Iapetus
Youtube: Iapetus Retro Stuff
User avatar
Chema
Game master
Posts: 3013
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Re: Sprites

Post by Chema »

Algarbi wrote:At the moment my routine is not optimised, I just wanted to see if things were working. So I am adding 40 at every line to the low byte of the zp pointer and then add one to the high byte if carry is set but I knew this could done in another away, absolute addressing as you said.

Thank you for the hints on using a back-screen buffer rectangle, that is interesting, I just will have to figure out the best way to dump it to the real screen the fastest way possible. The play area takes only 3840 bytes.
Hi Algarbi. This is an interesting subject. If your sprites never overlap, you can save the background and dump it back when necessary, but this won't work if the sprites overlap and will produce flickering if the sprite moves to a position where it overlaps with the previous image (restore background, redraw).

Have you read my posts about Skool Daze? There are several possibilities here:
- Use a big backbuffer where you can draw the sprites and dump it to the screen quickly. This was done in some speccy games (Cobra, for instance, IIRC), where they used the stack to dump the big buffer back to screen. You have to do the following each frame:
1. clear the buffer
2. draw the background
3. plot the sprites (with masking)
4 dump the buffer.

Even scrolling is simple in this schema. Something similar, but without sprites was done in 1337. The key point here is how to do this at a decent speed (10 fps might be the minimum, for a quick shoot'em up or platform game). The fastest way to clear and dump the buffer (of width WIDTH, and 122 rows) I found was:

Code: Select all

clear_buffer
.(
	ldx #WIDTH
	lda #$40
loop
	sta buffer+LEFT+40*0,x
	sta buffer+LEFT+40*1,x
	sta buffer+LEFT+40*2,x
	...
	sta buffer+LEFT+40*119,x
	sta buffer+LEFT+40*120,x
	sta buffer+LEFT+40*121,x
	dex
	bmi end
	jmp loop
end
	rts
.)

dump_buf
.(
	ldx #WIDTH
loop
	lda buffer+LEFT+40*0,x
	sta $a000+LEFT+40*(0+TOP),x
	lda buffer+LEFT+40*1,x
	sta $a000+LEFT+40*(1+TOP),x
	lda buffer+LEFT+40*2,x
	sta $a000+LEFT+40*(2+TOP),x
            ...
	lda buffer+LEFT+40*120,x
	sta $a000+LEFT+40*(120+TOP),x
	lda buffer+LEFT+40*121,x
	sta $a000+LEFT+40*(121+TOP),x
	dex
	bmi end
	jmp loop
end
	rts
.)

It takes a lot of memory and is not as fast as I wanted. Surely you get the idea.

-Another possibility is minimizing the parts you need to clear/dump, using something like dirty rectangles (search for it in wikipedia). Basically calculate the areas that need redrawing and clear/draw/dump only those.

If you cannot afford that, due to memory reasons or because your drawing takes too much time, you can use a small backbuffer for redrawing the area around the sprite that has just moved, then dump it. I used that in Space:1999. Basically you have to calculate the rectangle that needs updating due a sprite movement and draw in the backbuffer the background objects and sprites that overlap with that area (you need to implement clipping in your drawing routines). Then dump the buffer (which may only need to be something like 4x15) to the screen.

-However this is not fast if you have many sprites moving and overlapping, as it will redraw the same area several times. In that case there is another solution, which is kind of a middle point between all the above. That is the technique used in Skool Daze, where the backbuffer is only one tile (less than the sprite size) and there is an additional bitmap field where you mark all the tiles that need redrawing. After all your sprites moved, you check that bitmap and redraw/dump only what is necessary, and only once.

One last thing. You can do a super-optimized clearing/dumping routine using a lot of memory and still have a dead slow framerate if your sprite/background drawing routines are not ultra-fast. So first make sure you have good routines for those (as Dbug said, use self-modifying code, unroll loops, etc) and be sure you can access data in memory (where your background, sprite and mask graphics are) as fast as possible. Again I give some hints about how that could be achieved in my posts about Skool Daze.

I have been thinking about this for a while, as inspiration for a possible next game... but nothing clear in my mind about it yet. Just some ideas about what I would like to experiment with.

Cheers.
User avatar
Iapetus
Flying Officer
Posts: 135
Joined: Thu Mar 19, 2009 10:47 pm

Re: Sprites

Post by Iapetus »

Chema, thank you so much for such priceless info(both here and in your other threads where you explain how you code your games).
Twitter: @newIapetus
Ko-fi:iapetusretrostuff
itch.io: Iapetus
Youtube: Iapetus Retro Stuff
User avatar
Iapetus
Flying Officer
Posts: 135
Joined: Thu Mar 19, 2009 10:47 pm

Re: Sprites

Post by Iapetus »

Finally I had some time to work a bit more in this project...

I have now my buffers and 4 sprites (masked) working but all moves so slowly. It must be because I am using the following approach:

- Play area : 24x160
- buffer for the background 24x160
- second buffer where I paint the sprites 28x176

I paint the background tiles then copy the background buffer to the second buffer and then paint the sprites and finally I copy this second buffer to the screen.

I suspected this would be too slow but I wanted to have something working first, now I must work upon this result and solve the issue of extreme slow speed :)

My routines to copy the buffers are like that one Chema presented above.
Twitter: @newIapetus
Ko-fi:iapetusretrostuff
itch.io: Iapetus
Youtube: Iapetus Retro Stuff
User avatar
Chema
Game master
Posts: 3013
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Re: Sprites

Post by Chema »

Hi Algarbi.

Clearing and dumping the buffer with the above routines is slow, but you should get something like 12 fps easily. You may want to check this alone (without drawing background or sprites) and see there is no problem here.

Then you may want to add the drawing of the background. This could be a bottleneck indeed, unless you are very careful. If you are drawing the whole background at each frame, speed will surely drop to somehting unusable. This depends on how you draw the background of course, and the area you are updating (the whole background or only those parts that need to be updated).

When you have something like 10 fps with this, you can try to add the sprites and see what happens. With good optimized code, and not many many sprites, it should be quite fast.

For getting the timing there are several alternatives. One is to use the Oric timers and calculate the ticks spent per frame and print that onscreen (for instance in the one of the three lines of text).

Another alternative is using Oricutron's debugger which is able to count cycles. I don't remember the commands here, so you should check the readme, but it is something like setting two breakpoints, one at the start of the render code and another at the end. When the prog stops at the first breakpoint pressing a key (don't remember which) resets the cycle counter. Then continue the execution and when it stops again see the value of the counter.

Could give more information if you need it a bit later (need to check my code and Oricutron's readme).

Good luck. I will be watching this, as I am particularly interested.
User avatar
Iapetus
Flying Officer
Posts: 135
Joined: Thu Mar 19, 2009 10:47 pm

Re: Sprites

Post by Iapetus »

I only paint the background once in a buffer then I copy it each time to the other buffer to paint the sprites.

Thank you for the hints on checking the timing. I did saw that on oricutron, one can use F9 to reset cycles, I will check the docs to see how to use this feature.

At first I thought of having my sprite data, first all the 16 lines of the mask and then the sprite. But while coding yesterday I decided to do it interleaved, and using an index, y in this case, I can paint 10 lines without using adc. I am using selfmod code to poke the source and destination at the right places.
Twitter: @newIapetus
Ko-fi:iapetusretrostuff
itch.io: Iapetus
Youtube: Iapetus Retro Stuff
User avatar
Chema
Game master
Posts: 3013
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Re: Sprites

Post by Chema »

One sec...
Algarbi wrote:
I paint the background tiles then copy the background buffer to the second buffer and then paint the sprites and finally I copy this second buffer to the screen.
Why these two backbuffers? This will reduce your framerate dramatically... Is it to avoid redrawing the background tiles? (so after the initial tile drawing, you just copy the first onto the second...) If that is the case, you will surely need to copy just the areas that changed, or it will be dead slow for sure.

EDIT: Our posts crossed... The answer to this is on your previous post, sorry.
User avatar
Iapetus
Flying Officer
Posts: 135
Joined: Thu Mar 19, 2009 10:47 pm

Re: Sprites

Post by Iapetus »

I must try just to copy the section of the background that will be painted on(a bit bigger actually).
Twitter: @newIapetus
Ko-fi:iapetusretrostuff
itch.io: Iapetus
Youtube: Iapetus Retro Stuff
User avatar
Dbug
Site Admin
Posts: 4437
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: Sprites

Post by Dbug »

If you go for the "blit rectangles" method, you can kill two birds with one stone. The same loop that blits the rectangle from your composition buffer to the screen can also get the background data from the other buffer to after you are done blitting your composition buffer is totally clean again.
This avoid a full blit of the clean background to the second buffer.
User avatar
Iapetus
Flying Officer
Posts: 135
Joined: Thu Mar 19, 2009 10:47 pm

Re: Sprites

Post by Iapetus »

Ta _Dbug_

Can you elaborate a bit more how this "blit rectangles" technique would work, please?
Twitter: @newIapetus
Ko-fi:iapetusretrostuff
itch.io: Iapetus
Youtube: Iapetus Retro Stuff
User avatar
Dbug
Site Admin
Posts: 4437
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: Sprites

Post by Dbug »

Well, ideally you would build a list of "dirty rectangles":
- old position of the sprites that need to be cleaned
- new position of the sprites

if you use an offscreen buffer, all you need is to copy these rectangles to the screen, and this will automagically delete the old position and draw the new sprite. Do that for each sprite.

You have two ways basically to compute/use the dirty-rectangles:
- either you keep the old positions/new positions and compute the size of the rectangle that enclose all that, but it can be slightly difficult and annoying because the size changes depending of the direction of the movement and if they move at all
- or if your sprites move slowly, then you can just have a single "bigger" blit rectangle, which is defined as the new position of the sprite, plus few scanlines above, few scanlines under, one byte more on the left and one byte more on the right. This gives you a fixed size rectangle that you can optimize by hardcoding the copy loop.

If you do that, then you can do the second phase of optimization, which is to make the blit rectangle perform two functions:
- blit the offscreen buffer to the screen
- recopy the background into the offscreen buffer
this way at the end of the blit the offscreen buffer is ready for new sprites
(please note that this can be a problem if you have overlapping sprites because then you will redraw the now cleaned data)

Really depends of the scenario.

But in any case, blitting/cleaning small rectangles is still going to be faster than doing a full buffer recopy.
User avatar
Iapetus
Flying Officer
Posts: 135
Joined: Thu Mar 19, 2009 10:47 pm

Re: Sprites

Post by Iapetus »

Thanks Dbug,

I am doing part of that already it seems. I am keeping the old coordinates of the sprites and then I paint repaint those rectangles using the back buffer.

The speed is a bit better now that I am not dumping all the background. I will now try to improve my paint_sprite routine, I know that some things could be done another away.
Twitter: @newIapetus
Ko-fi:iapetusretrostuff
itch.io: Iapetus
Youtube: Iapetus Retro Stuff
User avatar
Iapetus
Flying Officer
Posts: 135
Joined: Thu Mar 19, 2009 10:47 pm

Re: Sprites

Post by Iapetus »

Hello, finally I am back to my game project.

I have started from scratch and I have the sprite engine working now, although I am thinking of optimizing it still as at the moment I am copying the whole buffer in one go and if I only copy the sprite areas I might get a nice speed boost.

This is how it is running at the moment.

http://www.youtube.com/watch?v=rrr1wNzUxQ0
Twitter: @newIapetus
Ko-fi:iapetusretrostuff
itch.io: Iapetus
Youtube: Iapetus Retro Stuff
Post Reply