Edge Grinder for the Spectrum

Show us what you're working on, (preferably with screenshots).
Post Reply
User avatar
R-Tape
Site Admin
Posts: 6353
Joined: Thu Nov 09, 2017 11:46 am

Re: Edge Grinder for the Spectrum

Post by R-Tape »

Ast A. Moore wrote: Mon Nov 13, 2017 3:34 pm
R-Tape wrote: Sun Nov 12, 2017 3:39 pm I want it to run without a HALT for speed reasons, so AY will be an issue.
Use the floating bus trick for syncing and IM2 for music only?
I'm outside my comfort zone already. I understand how to use the floating bus to wait for the top or bottom part of the screen, but I don't see how it helps here. Wouldn't the program still need to wait for the fb?
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2640
Joined: Mon Nov 13, 2017 3:16 pm

Re: Edge Grinder for the Spectrum

Post by Ast A. Moore »

R-Tape wrote: Mon Nov 13, 2017 4:10 pm
Ast A. Moore wrote: Mon Nov 13, 2017 3:34 pm Use the floating bus trick for syncing and IM2 for music only?
I'm outside my comfort zone already. I understand how to use the floating bus to wait for the top or bottom part of the screen, but I don't see how it helps here. Wouldn't the program still need to wait for the fb?
Well, the FB can land you fairly reliably on any part of the screen, not just the top or bottom (so you can start updating the top of the screen, say, right before the raster lands on the status panel). But yes, the program will sit in a loop waiting for the expected byte to appear on the data bus. The disadvantage is that you lose it when the screen data in that particular area changes, which is okay for gameplay, generally speaking, but not okay if you want the music to keep playing. That’s why I suggest syncing the music player to interrupts and screen updates to the FB.

Just a suggestion, of course. It’s all pretty case-specific.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Ralf
Rick Dangerous
Posts: 2279
Joined: Mon Nov 13, 2017 11:59 am
Location: Poland

Re: Edge Grinder for the Spectrum

Post by Ralf »

Not this one - I started it around May this year, with EG specifically in mind.
So I must have been confusing it with some other project, these space shootemups are a bit similar, aren't they? ;)

I had the chance of running it now.

It's a really good engine. You have a chance to make a second Zynaps :)

At this moment there is bad colour clash but I'm sure it will be gone in final version.

Good luck with it!
AndyC
Dynamite Dan
Posts: 1388
Joined: Mon Nov 13, 2017 5:12 am

Re: Edge Grinder for the Spectrum

Post by AndyC »

There was definitely some talk of how you could do it, back when the game originally came out for the C64 and CPC. Don't remember anyway actually starting it though. Looking forward to seeing how it comes out. :)
User avatar
R-Tape
Site Admin
Posts: 6353
Joined: Thu Nov 09, 2017 11:46 am

Re: Edge Grinder for the Spectrum

Post by R-Tape »

Ralf wrote: Mon Nov 13, 2017 9:01 pm It's a really good engine. You have a chance to make a second Zynaps :)
:shock:
AndyC wrote: Mon Nov 13, 2017 11:53 pm There was definitely some talk of how you could do it, back when the game originally came out for the C64 and CPC. Don't remember anyway actually starting it though. Looking forward to seeing how it comes out. :)
Cheers.

I've had a few chats about how to do it and here's the reasoning behind my design choices:

The main problem is speed, 12.5fps (main loop takes 3 frames) looks too slow. How to rotate the buffer and move it to the screen fast enough?

The options:

RL (HL) the buffer and LDI to the screen. More Tea Vicar does this, and while that's a great game it's farrr to slow for this.

RLD the buffer and PUSH to the screen. Like a faster Cronos (but that uses LDI). Would look fast but jerky. Maybe.

PUSH scroller. Like Cobra, Steel Eagle, 50Hurts and CATs engines. Easily 25fps and very fast but you are forced to use simple graphics.

Rotate on the screen. The Zynaps and R-Type scroller. Scroll the blocks on the screen, not the empty space. no need to move a buffer to the screen. Huge time saving and probably the best way to do it, the small downside is that background interaction with sprites sometimes looks a bit odd. Trouble is, as beautifully simple as the concept is, I can't do it. I've tried it a few times and it melts my brain.

RL (HL) the buffer and PUSH to the screen with a HALT in the code. Ends up a constant 12.5 fps at best. Too slow.

RL (HL) the buffer and PUSH to the screen, no HALT, not constant frame rate.

So I went with the last one. So far the speed is okay and I don't have much more to add. To PUSH the screen takes 2/3 of a frame and RL (HL) the buffer is 1 frame, add the rest of the code and it takes ~2 and a third frames per pass of the main loop.
Ralf
Rick Dangerous
Posts: 2279
Joined: Mon Nov 13, 2017 11:59 am
Location: Poland

Re: Edge Grinder for the Spectrum

Post by Ralf »

Rotate on the screen. The Zynaps and R-Type scroller. Scroll the blocks on the screen, not the empty space. no need to move a buffer to the screen. Huge time saving and probably the best way to do it, the small downside is that background interaction with sprites sometimes looks a bit odd. Trouble is, as beautifully simple as the concept is, I can't do it. I've tried it a few times and it melts my brain.

I have an unfinished project using this technique. I'll try to write more about it later in programming section.
User avatar
Ivanzx
Manic Miner
Posts: 736
Joined: Tue Nov 14, 2017 9:51 am

Re: Edge Grinder for the Spectrum

Post by Ivanzx »

Considering that this is an early stage, it is looking good! I have to check the C64 and CPC versions too ;)
User avatar
Joefish
Rick Dangerous
Posts: 2042
Joined: Tue Nov 14, 2017 10:26 am

Re: Edge Grinder for the Spectrum

Post by Joefish »

To speed up your buffer scroll:

Align it with a memory address divisible by 32, then use SLA (HL) for the first byte, RL (HL) for subsequent bytes. Use DEC L between bytes and only use DEC HL at the end of a row.

To optimise it more, make two instruction buffers(one for each third of the screen you're scrolling) and allocate it two bytes per character (2 bytes x 8 rows x 32 chars). Put in the SLA (HL), DEC L, RL (HL), DEC L, ... RL (HL), DEC HL eight times for each row. And call each one 8 times. That scrolls your screen buffer.

Now the trick is, you can actually put in NOPs instead of RL (HL) where there is no data to scroll, and so save time. And you can shift the SLA (HL) / RL (HL) / NOP bytes 2-bytes to the left to shift your pattern along one character to the left as the screen and attributes move. And fill in SLA (HL) / RL (HL) / NOP instructions from the right depending on whether grpahics are present or not. (You could optimise this further, but then you end up with variable-length lines in your instruction list).

You can apply this technique to the buffer or to the screen. R-Type re-generates its list of scrolls on-the-fly. You don't need to do that if your scenery isn't changing.

The trick with scrolling the screen like this is a sprite engine that draws character-by-character and can stop drawing if some scenery is already there (use 0-attributes in the scenery to designate empty cells).
Hikaru
Microbot
Posts: 100
Joined: Mon Nov 13, 2017 1:42 pm
Location: Russia
Contact:

Re: Edge Grinder for the Spectrum

Post by Hikaru »

R-Tape wrote: Tue Nov 14, 2017 7:16 amRotate on the screen. The Zynaps and R-Type scroller. Scroll the blocks on the screen, not the empty space. no need to move a buffer to the screen. Huge time saving and probably the best way to do it, the small downside is that background interaction with sprites sometimes looks a bit odd. Trouble is, as beautifully simple as the concept is, I can't do it. I've tried it a few times and it melts my brain.
I'm not sure how you're doing sprite/bg collision testing, but if we take that out of the picture for a moment, then a variant of this would really only need a minor modification on top of what you already have.

1. XOR out the sprites
2. Rotate the bg in place
3. XOR in the sprites

Do this in a top to bottom fashion, for instance using 2 passes for a start (third 1, third 2). In this case, you'll need to start when the raster is approaching third 2. It's a bit hard to estimate the actual speedup because, although you would no longer have the 'buffer copy' phase, you would have the 'XOR out the sprites' phase instead, and also the rotating would occur in contended memory which is slower. But in any case I'm pretty sure it will be fairly significant and would probably allow for 25FPS + HALT.

Regarding skipping over the empty space (R-Type like). This is an option but is significantly more work compared to the above, and it might not necessarily give an improvement. For instance if there's lots of bg anyway, it might be more effective to just rotate everything in an unrolled loop.

Regarding the AY music, specifically if you want the AY music player to run at 50Hz but it's inconvenient for some reason. Typically, AY players have a buffer for AY register values which are OUTput at the end of its execution, independently from parsing the song data. It's possible to separate the parsing stage and the OUTput stage completely in the player code, so instead of a single CALL Player, you would have two: CALL ParseSong: CALL OutputAYRegs. In that case, you can do this. After a HALT, do CALL ParseSong: CALL OutputAYRegs: CALL ParseSong. Then after 'roughly' a frame worth of other tasks (a second HALT might be useful here), CALL OutputAYRegs again. Due to the fact that the OUTput stage itself is fairly fast, it shouldn't disturb the flow of your other procedures much, even if this has to happen amidst the 'critical' screen stuff updates.
Inactive account
AndyC
Dynamite Dan
Posts: 1388
Joined: Mon Nov 13, 2017 5:12 am

Re: Edge Grinder for the Spectrum

Post by AndyC »

If you need the AY routine to be called at 50fps but don't want to wait for HALTs, why not just call it from within the interrupt handler itself? Your music might go iffy I suppose if you DI for too long, but that's probably as true for any other strategy. Alternatively count frames in the interrupt handler, call a music handler whenever you can and only have that actually call the real AY routine if the frame count has increased.
User avatar
R-Tape
Site Admin
Posts: 6353
Joined: Thu Nov 09, 2017 11:46 am

Re: Edge Grinder for the Spectrum

Post by R-Tape »

Thanks for the tips Joe and Hikaru, they'll need some processing time (in my head not the z80).
AndyC wrote: Tue Nov 14, 2017 6:34 pm If you need the AY routine to be called at 50fps but don't want to wait for HALTs, why not just call it from within the interrupt handler itself? Your music might go iffy I suppose if you DI for too long, but that's probably as true for any other strategy. Alternatively count frames in the interrupt handler, call a music handler whenever you can and only have that actually call the real AY routine if the frame count has increased.
I haven't tested it yet but I think it's sure to sound wonky, interrupts have to be disabled for around 15% of the time during screen PUSH.

I've tried this with an AY tune* and (you'll be horrified I'm even considering it!) and I think it sounded okay. The main loop looks something like this:

CALL AY
a bit of stuff
rotatebuffer
CALL AY
xor stuff ON
push buffer to screen
xor stuff OFF
most other stuff

The distance between the two CALL AYs can be placed as close as possible to a frame apart, a lot of the routines have been written so they don't vary that much, e.g. if a sprite is off still draw it but elsewhere.

It's icky, but if it works I'll be happy.

When everything's in place I'll need to see how well I can refine it, barring a complete redesign or calling it a AY free first attempt.

*not the Edge Grinder track, which I still need to commission or get my hands on the CPC version.
Post Reply