News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

hardware scrolling

Started by arnoldemu, 11:28, 04 January 25

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

arnoldemu

A few years back I wrote a document about hardware scrolling and various methods to use.
I went all in the past year or two and I present more examples and the code.

TL;DR:
* smoothing vertical scroll is not an issue, we have various methods that work with modern devices.
* Drawing on the screen can be a bit more expensive for CPU time but we can with some game designs avoid that issue all together.
* smoothing horizontal scrolling is a bit troublesome: using R3 has been an issue and may be more of an issue with modern display devices as it doesn't work on some.


I chose to split the code into 'include' and a file per example. I tried to keep each example similar so it is more obvious to spot the key thing being demonstrated.

In these I refer to the 'problem area'. It is the discontinuity in the memory addresses so that a INC doesn't go to the next byte to the right and happens where the screen wraps. The addresses for a screen at &c000 are &C7FF->&C000, &CFFF->&C800, etc. To handle this discontinuity requires additional code if anything is drawn over it (mainly affects sprites) so some examples show how it can be avoided or detected so we can use faster drawing.

I've also split the examples into multiple dsks. Some of these examples have been presented before in this forum.

Plus
* mode 0 pixel by pixel scroll
* mode 1 pixel by pixel scroll
* mode 0 pixel by pixel scroll and hide left column
* pixel by pixel scroll with a panel at the top (R12/R13 define the panel location and the split address defines the scroll location)
* pixel by pixel scroll with a panel at the bottom (R12/R13 define the scroll location and the split address defines the panel location)

CPC (which can also run on Plus)
* Standard 'chunky' all directional scroll.
* Diagonal 'chunky' all directional scroll (45 degree diagonal movement)

* Horizontal scroll only limited so that the problem area never appears in the middle of the screen.
(tradeoff reduced vertical height but could be coupled with a panel using rupture). Used by Action Force.
* Vertical scroll only which is continuous but the width is adjusted so the problem area lies on the left or the right (used by mission genocide)
* Both horizontal and vertical which is limited.
* Continous scroll but we detect if we are above, below, to the left, to the right or over the problem area to make a decision about which sprite routine could be used. (bit of time required for detection)

* Scrolling a 32KB overscan screen horizontally. (Limited due to the wrap around working for 16kb only)
* Scrolling a 32KB overscan screen vertically. (limited due to the wrap around working for 16kb only)
* Scrolling a overscan screen using rupture (aka 'crossfire') (which I've not tested on a real machine so might not work), splits the screen into two independent 16KB screens, with this one you need to consider how to render the sprite over the split. Used by 'return of the sisters ii'.

* Panel inside scroll at top: The panel is stored separately and copied into the screen memory at the right place. Used by games like 'Sly Spy'.
* Panel inside scroll at bottom. As for 'panel inside scroll at top' but at the bottom.
* Panel inside scroll at bottom which is hidden when scrolling (by changing R6). Same as panel inside scroll at bottom but it hides when scrolling as seen in 'Vikings'.
* Panel within scroll top. The panel doesn't use it's own memory and is moved in memory as the screen scrolls to correctly position itself. It's a bit more of a headache to handle.
* Panel within scroll bottom. The panel doesn't use it's own memory and is moved in memory as the screen scrolls to correctly position itself. It's a bit more of a headache to handle.

* Smoothing the scroll using R3 (and the better values discovered by Longshot). Works best on real monitor, on my television the whole screen is a bit distorted and jumps, on a LCD the R3 effect does nothing and it remains static.
* Smoothing the scroll using R5 (adding and removing lines). Works best on a real monitor as it's extending the frame time. Seen on 'LED Storm'.
* Smoothing the scroll using R9 (reduce the height of each char line) and scroll using 'chunky' in the example it is 4 lines vs 8 lines. (used by Druid 2 Enlightnment)
* Byte by byte smooth scroll by having one screen offset by a byte. The sacrifice is memory and cpu time to draw to it, careful drawing of sprites required to avoid additional flicker as it's not double buffered. Ok for any mode. May not work well if the scroll stops, would need a better example to know for sure.
* Pixel by pixel mode 0 smooth scroll by using R3 and a screen offset by a pixel. Same issues as Byte by byte plus those of R3. For mode 1 more screens are required for the pixel offsets and you run out of memory very quickly.

* When using R3 the sides of the screen flicker due to the pixels shifting back and forth, this attempts to solve that by drawing a column of colour the same as the border down the sides. It is a proof of concept so is not optimised only really will work well with double buffer and then it needs additional ram for the columns to restore them back.
* When using R5 the top and bottom of the screen flicker, use R1 to hide the lines. Ok but may need to burn cpu cycles to get the right place to do this.
* When using R5 the top and bottom of the screen flicker, we will blank them using the same colour as the border and hide it. Likewise with the R3 example it is a proof of concept and needs double buffering to be effective. It too needs additional ram to store the rows to restore back.

* Move a sprite pixel by pixel over a screen that is slowly scrolling horizontally. This is embracing the chunky scroll and it's comparable to Nemesis on the MSX1.
* Move a sprite pixel by pixel over a screen that is slowly scrolling vertically. More for completeness as smoothing vertical scroll is easy to achieve and compatible with all display when done using rupture.
* move a sprite pixel by pixel and as you approach the side scroll some amount of the screen in one quick movement. This includes ones where the enemies don't update and one where they do - but not obvious in the example. (e.g. Monty Python's Flying Circus)
* move a sprite at the same rate as the scroll and as you get to the centre scroll with it keeping it central (Turrican)

Enjoy :)





My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

I forgot to attach the dsk with the plus examples. Here it is.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

roudoudou

Quote from: arnoldemu on 11:28, 04 January 25In these I refer to the 'problem area'. It is the discontinuity in the memory addresses so that a INC doesn't go to the next byte to the right and happens where the screen wraps. The addresses for a screen at &c000 are &C7FF->&C000, &CFFF->&C800, etc. To handle this discontinuity requires additional code if anything is drawn over it (mainly affects sprites) so some examples show how it can be avoided or detected so we can use faster drawing.

Why calling this "discontinuity" when it's literally a continuity inside the block ;D

I made some visuals example of scrollings with that "reloop inside block" part (BLUE vertical line), and "high-byte changing" part (RED vertical line)



The articles are in french, maybe someone can help for translations (or i will do this later...)

andycadley

Wow, sounds comprehensive.  :) Will have to have a look through them all at some point, to see if there are any tricks I've missed.

The only thing I can think of was my way of doing a Plus 32K overscan scroll. Which used the rather obvious method of putting the split mid screen and scrolling both sections - requires a bit more drawing as things cross the boundaries, but it's more affordable with hardware sprites.

norecess464

Quote from: andycadley on 12:25, 04 January 25The only thing I can think of was my way of doing a Plus 32K overscan scroll. Which used the rather obvious method of putting the split mid screen and scrolling both sections - requires a bit more drawing as things cross the boundaries, but it's more affordable with hardware sprites.
If you use a static split screen positioned in the middle of the screen, you need to draw twice the horizontal lines required to achieve vertical scrolling (one per frame buffer).

SonicGX, however, uses three split screens for worst cases ("PAGE A -> PAGE B -> PAGE A") with a continuously changing Y position for the splits. This approach ensures that the same 32KB screen buffer is being reused, requiring only a single pass to draw the horizontal lines.

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!

andycadley

Quote from: norecess464 on 14:34, 04 January 25
Quote from: andycadley on 12:25, 04 January 25The only thing I can think of was my way of doing a Plus 32K overscan scroll. Which used the rather obvious method of putting the split mid screen and scrolling both sections - requires a bit more drawing as things cross the boundaries, but it's more affordable with hardware sprites.
If you use a static split screen positioned in the middle of the screen, you need to draw twice the horizontal lines required to achieve vertical scrolling (one per frame buffer).

SonicGX, however, uses three split screens for worst cases ("PAGE A -> PAGE B -> PAGE A") with a continuously changing Y position for the splits. This approach ensures that the same 32KB screen buffer is being reused, requiring only a single pass to draw the horizontal lines.


Sneaky. I did have a routine that used three segments and moved the boundaries, but that was mostly so I could pull off some R-Type 3 (on the SNES) type tricks to give the impression of parallax layerings by scrolling segments at different speeds, with occasional sprites standing in for background layers that overlap the split to sell the idea better.

Powered by SMFPacks Menu Editor Mod