News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_zhulien

Sprites Tiles and other superfast screen output approaches

Started by zhulien, 13:02, 03 February 23

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

zhulien

The questions I have here are most about CPC but the plus models might have some additional tricks.

As I was writing a sprite library I have been thinking of different approaches, especially since cpc can have lots of RAM and ROM.

Traditionally a software sprite might have some data and a fairly generic way to copy that to a location on the screen, perhaps anywhere.  It could have a mask or use xor to make it non detectructive.  To me this is tried and tested and also likely the slowest but gives a fair amount of flexibility for code size.  Perhaps a good use of this would be to construct a playfield dynamically in a nonscrolling single screen game.

Some optimisation I can think of above if a sprite was to move non destructive over a nice backdrop could be to keep an entire copy of that backdrop also somewhere in memory effectively creating backdrop sprites where ever a backdrop needs replacing. This means we don't need to capture a backdrop dynamically before placing a sprite at the expense of memory.

Then we have what I'd call a compiled sprite. Is this what is generally considered a compiled sprite? Eg. Ld hl.%c000; ld a,255; ld (hl), a

That would put a 1 byte compiled sprite on the screen.  I can see this removes need of looping and lookups to make a sprite as fast as possible (i think) and depending how much flexibility is required for placement then various branches and/or lookups would be used multiplying the amount of code necessary for a compiled sprite.  The amount of code and speed directly relates to the size and complexity (the colour makeup) of the sprite.  And how intelligent the sprite compiler can be.  This also might be good if the z80 did sprite compilation between levels perhaps, of just take more secondary storage for precompiled sprites to be stored.

Back to sprites and then vectors.  Is it faster to draw lines, or draw the result of compiled vector polygons to sprites?

If compiled sprites were used for tiles also, and perhaps scrolling, create compiled character height (for top bottom vertical scrolling)?  I haven't looked at eg... how Alcon works but I was thinking what if the entire screen was a sequence of compiled pixel high or character high sprites?  Super fast rendering?  At least for the scrolling.

Any other better methods or criticisms to the above methods?

gurneyh

I don't think we can get a satisfactory generic version on our old machines.

You talk about alcon but, it's a special case, vertical scrolling with reduced screen width.

Really, we have to think about the optimal solution on a case by case basis. And if not, what would be the interest to develop on 8/16 bits?

norecess464

Hello!

Before anything, I would suggest to reduce the scope of the topic to 1 or 2 specific questions, otherwise it's going to be too vast to be discussed :)
My personal website: https://norecess.cpcscene.net
My current project is Sonic GX, a remake of Sonic the Hedgehog for the awesome Amstrad GX-4000 game console!

TotO

Quote from: gurneyh on 14:53, 03 February 23You talk about alcon but, it's a special case, vertical scrolling with reduced screen width.
It is the arcade scrolling and screen width.
"You make one mistake in your life and the internet will never let you live it down" (Keith Goodyer)

TotO

@zhulien I think that you can't provide a generic way to display sprites without defining some set of screen modes to use together. If the goal is to allow people to easy program arcade games on CPC and not have to took care about the technical side but more the gameplay side, they will do with, if the result worth it. 256x224+32, 256x256, 128x224+32, 128x256 is a good start.
"You make one mistake in your life and the internet will never let you live it down" (Keith Goodyer)

roudoudou

there is already some (old) topics about drawing optimisations, take a look with "fast" "drawing" "optimisation"
My pronouns are RASM and ACE

Sykobee (Briggsy)

From previous discussions it seems that generic routines are good for early development, but you should then optimise and select the most appropriate sprite/tile mechanisms once your design is more grounded and you know what you need, and you need the clock cycles.

Obviously with cartridges (even on a standard CPC) and extra RAM systems, compiled sprites are very viable across the board. For a 64KB game perhaps only very specific sprites (bullets (small, lots of them), player (always visible)).


zhulien

If only the CPC had a better way to address screen positions - to make any sprite routines less calculation intensive.

gurneyh

Quote from: TotO on 15:52, 03 February 23
Quote from: gurneyh on 14:53, 03 February 23You talk about alcon but, it's a special case, vertical scrolling with reduced screen width.
It is the arcade scrolling and screen width.
It was not a criticism. Just a special case like many games!

TotO

Sure, it is not a 40x25 but 32x32 screen to have a vertical "overscan".
"You make one mistake in your life and the internet will never let you live it down" (Keith Goodyer)

gurneyh

Quote from: zhulien on 17:52, 03 February 23If only the CPC had a better way to address screen positions - to make any sprite routines less calculation intensive.
there are solutions! But you need to be more specific in your questions :)


roudoudou

My pronouns are RASM and ACE

Anthony Flack

#12
A few things:

First the obvious - use a lookup table to get the y address and then add x.

To jump to the line below the current line, you can use something like:

NewLine:
  LD A,H:ADD C:LD H,A ; character line jump
  AND &38: RET NZ ; if we're not at the end of the character line, we're done
  ADD HL,DE ; next character line
RET

nb. you should LD C,&8:LD DE,&c040 before you start. I'm assuming that the screen address is in HL. You could use ADD &8 instead of ADD C if C is in use already, but ADD C is faster.

You can use an unrolled 8 line loop and jump in part way through to avoid checking for the end of the character line.

If you are on an even scanline, you can jump to the next line down with a simple SET 3,H. This is an easy speed increase if you don't mind your sprites moving up or down in steps of two scanlines.

If you are on the top line of a character, you can access all the lines (out of order) like so:

;start on line 0
SET 3,H ; line 1
SET 4,H ; line 3
RES 3,H ; line 2
SET 5,H ; line 6
RES 4,H ; line 4
SET 3,H ; line 5
SET 4,H ; line 7

This can be useful for drawing things like tiles.

Draw alternating lines from left to right, then right to left to avoid having to reset the X position every line.

Anthony Flack

#13
I should add - pretty much all of the above has been mentioned on the wiki already, in various places - but those are the things I personally have found most useful for improving the line jump. For narrow sprites especially, it can make quite a difference depending how you do it.

Oh, and come to think of it - those numbers are for a 64 byte wide screen, not 80 bytes. That also helps.

zhulien

Quote from: Anthony Flack on 00:47, 04 February 23A few things:

If you are on an even scanline, you can jump to the next line down with a simple SET 3,H. This is an easy speed increase if you don't mind your sprites moving up or down in steps of two scanlines.

If you are on the top line of a character, you can access all the lines (out of order) like so:

;start on line 0
SET 3,H ; line 1
SET 4,H ; line 3
RES 3,H ; line 2
SET 5,H ; line 6
RES 4,H ; line 4
SET 3,H ; line 5
SET 4,H ; line 7
Awesome, I never considered to use Set to move down.

zhulien

Is there already a very good PC to CPC sprite compiler?

BSC

Quote from: Anthony Flack on 00:47, 04 February 23A few things:

First the obvious - use a lookup table to get the y address and then add x.
[...]

Great collection of advice! All of this should be in the actual Wiki instead of being scattered all about the forums. Ideally addressable from a kind of wiki hub. Or maybe I missed that that's already there..?
** My SID player/tracker AYAY Kaeppttn! on github **  Some CPC music and experiments ** Other music ** More music on scenestream (former nectarine) ** Some shaders ** Some Soundtrakker tunes ** Some tunes in Javascript

My hardware: ** Schneider CPC 464 with colour screen, 64k extension, 3" and 5,25 drives and more ** Amstrad CPC 6128 with M4 board, GreaseWeazle.

roudoudou

Quote from: BSC on 12:13, 04 February 23
Quote from: Anthony Flack on 00:47, 04 February 23A few things:

First the obvious - use a lookup table to get the y address and then add x.
[...]

Great collection of advice! All of this should be in the actual Wiki instead of being scattered all about the forums. Ideally addressable from a kind of wiki hub. Or maybe I missed that that's already there..?

the Amstrad knowledge available is relative to Amstrad programmers. Low as we are only a few people.

+ it's time consuming to write articles, etc.

if you have time, feel free to gather everything already on forums ;)
My pronouns are RASM and ACE

Anthony Flack

Honestly, the Amstrad knowledge available is huge, and it's brilliant. The CRTC Compendium that was released recently, wow. Far more information than we ever had during the machines' commercial life. 

I don't know about sprite compilers, that's a good question. I tend to write my own tools for that kind of thing, but they're not general purpose or fit for pubic release.

zhulien

How many hw sprites can we have on 6128 plus? The wiki says 16 per scan line, but we have lots of scan lines... if sprites are also 16x16, then we can fill 256x200 with sprites?

roudoudou

you can have more than 16 sprites in a row (time consuming, not really usable)
you can multiplex easily sprites positions, see https://www.cpc-power.com/index.php?page=detail&num=17425 (all red bullets are in reality 3 sprites)
but when you change a sprite position, the position is changed (no sh1t sherlock!) so it wont appear where it was previously, until you change again his position.
if you take a look at Sonic preview from NoRecess, you can see some vertical rows of rings (which are obviously multiplexed)
in the prehistorik 2 game, the tree trunk is made with multiplexing and the leaf too (two trees below two trees)
My pronouns are RASM and ACE

andycadley

Quote from: zhulien on 18:27, 05 February 23How many hw sprites can we have on 6128 plus? The wiki says 16 per scan line, but we have lots of scan lines... if sprites are also 16x16, then we can fill 256x200 with sprites?
There are 16 sprites and you have to reload them by resetting all the pixels, which you can't do while they're on screen as the ASIC will automatically disable them while you're writing to them. So not much chance of covering 256*200 unless they're repeating images.

It's also possible, though difficult, to reuse the same sprite on a single line but again not practical in most cases.

BSC

Quote from: roudoudou on 12:24, 04 February 23
Quote from: BSC on 12:13, 04 February 23Great collection of advice! All of this should be in the actual Wiki instead of being scattered all about the forums. Ideally addressable from a kind of wiki hub. Or maybe I missed that that's already there..?
if you have time, feel free to gather everything already on forums ;)
I don't  ;)
** My SID player/tracker AYAY Kaeppttn! on github **  Some CPC music and experiments ** Other music ** More music on scenestream (former nectarine) ** Some shaders ** Some Soundtrakker tunes ** Some tunes in Javascript

My hardware: ** Schneider CPC 464 with colour screen, 64k extension, 3" and 5,25 drives and more ** Amstrad CPC 6128 with M4 board, GreaseWeazle.

arnolde

Quote from: Anthony Flack on 00:47, 04 February 23AND &38: RET NZ ; if we're not at the end of the character line, we're done
If you're only using the main screen (&C000-&FFFF), you don't even need AND &38, you can just RET C.
And if double buffering between &40 and &C0, I use ADD A:RET P instead, saves 1 byte & 1 nop

martin464

I think the great SET trick has another advantage if hardware scrolling by reg 12 and 13 which makes it even more awkward

normally getting next character pos you add 1 but it can wrap round in this case
so on INC HL have to RES 3, H, eg C7FF should go to C000 not C800

but if using SET it doesn't matter if bit 3 was set by the INC HL, cause that's what you want anyway

you can also use a different order to make HL ends up back on line 1 again so you can keep using it, or you could make it end up on the line you want HL to be on i guess. it adds 2 nops though for the extra set

00001000 +8
00011000 +16
00010000 -8
00110000 +32
00111000 +8
00101000 -16
00100000 -32
00000000 back to row 1
CPC 464 - 212387 K31-4Z

"One essential object is to choose that arrangement which shall tend to reduce to a minimum the time necessary for completing the calculation." Ada Lovelace

Powered by SMFPacks Menu Editor Mod