KEMBAR78
SDL: Fix shaking with SDL1 and negative offsets by phcoder · Pull Request #4754 · scummvm/scummvm · GitHub
Skip to content

Conversation

@phcoder
Copy link
Contributor

@phcoder phcoder commented Mar 1, 2023

Current code results in a crash

@criezy
Copy link
Member

criezy commented Mar 1, 2023

Note that the shake function is documented as taking only positive offsets:
https://github.com/scummvm/scummvm/blob/master/common/system.h#L1155-L1172

So passing negative offsets would be an error in the engine.

That being said, we should indeed avoid a crash. I am unsure about supporting this in some backends though. This may give the impression that negative offsets are supported, but the engine will then break on some other platform. Maybe it would be better to add a sanity check in the implementation of setShakePos to ignore negative offsets and print a warning?

@phcoder
Copy link
Contributor Author

phcoder commented Mar 1, 2023

Note that the shake function is documented as taking only positive offsets: https://github.com/scummvm/scummvm/blob/master/common/system.h#L1155-L1172

So passing negative offsets would be an error in the engine.

That being said, we should indeed avoid a crash. I am unsure about supporting this in some backends though. This may give the impression that negative offsets are supported, but the engine will then break on some other platform. Maybe it would be better to add a sanity check in the implementation of setShakePos to ignore negative offsets and print a warning?

This happens in the scumm engine on the day of tentacle on the scene with loud music which is unavoidable for walkthrough. Reading the code I see that scumm uses negative offsets: see method ScummEngine::updateScreenShakeEffect. On the other hand only 2 engines use negative shakes: SCUMM and KYRA

@criezy
Copy link
Member

criezy commented Mar 1, 2023

This happens in the scumm engine on the day of tentacle on the scene with loud music which is unavoidable for walkthrough. Reading the code I see that scumm uses negative offsets: see method ScummEngine::updateScreenShakeEffect.

This appears to be a fairly recent change from commit 33d1804. However it is not clear from the commit message and comment added in the code if changing from positive to negative offsets was intended. @athrxx can probably comment.

We could also decide to change the documentation to accept negative offsets if that is needed by some engines. But then we need to also modify all porters as the SDL1 backend may not be the only one not supporting it.

@athrxx
Copy link
Contributor

athrxx commented Mar 1, 2023

That change to negative offsets was actually intended, since that matches the shaking style of the original code (these offsets that get written into the crt controller registers of the VGA hardware will move the screen up, not down). (Just to make it more clear: the original code does write positive offsets, but they do have the opposite effect)

I only ever tested SDL2. I wasn't even aware that SDL1 was still much of a thing for us. With this fix we should probably update the documentation for that method to accept negative offsets.

Current code results in a crash
Copy link
Member

@criezy criezy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks mostly good. I have added two minor comments that can be ignored for code simplification, and a sanity check to avoid negative width or height in the case of a negative offset that moves a dirty rect fully outside the screen.

Comment on lines +1171 to +1178
SDL_Rect blackrect = {0, 0, (Uint16)(_videoMode.screenWidth * _videoMode.scaleFactor), (Uint16)(_videoMode.screenHeight * _videoMode.scaleFactor)};

if (_videoMode.aspectRatioCorrection && !_overlayInGUI)
if (_gameScreenShakeXOffset >= 0)
blackrect.w = (Uint16)(_gameScreenShakeXOffset * _videoMode.scaleFactor);
else {
blackrect.w = ((-_gameScreenShakeXOffset) * _videoMode.scaleFactor);
blackrect.x = ((_videoMode.screenWidth + _gameScreenShakeXOffset) * _videoMode.scaleFactor);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit of nitpicking, but this whole block could be simplified as follow:

SDL_Rect blackrect = {0, 0, (Uint16)(ABS(_gameScreenShakeXOffset) * _videoMode.scaleFactor), (Uint16)(_videoMode.screenHeight * _videoMode.scaleFactor)};
if (_gameScreenShakeXOffset < 0)
    blackrect.x = ((_videoMode.screenWidth + _gameScreenShakeXOffset) * _videoMode.scaleFactor);

Comment on lines +1192 to +1199
SDL_Rect blackrect = {0, 0, (Uint16)(_videoMode.screenWidth * _videoMode.scaleFactor), (Uint16)(_videoMode.screenHeight * _videoMode.scaleFactor)};

if (_videoMode.aspectRatioCorrection && !_overlayInGUI)
blackrect.h = real2Aspect(blackrect.h - 1) + 1;
if (_gameScreenShakeYOffset >= 0)
blackrect.h = (Uint16)(_gameScreenShakeYOffset * _videoMode.scaleFactor);
else {
blackrect.h = ((-_gameScreenShakeYOffset) * _videoMode.scaleFactor);
blackrect.y = ((_videoMode.screenHeight + _gameScreenShakeYOffset) * _videoMode.scaleFactor);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A similar simplification to what suggested above for the vertical black rect could also be applied here.

else
src_y += -_currentShakeYOffset;

if (dst_x < width && dst_y < height) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (dst_x < width && dst_y < height) {
if (dst_x < width && dst_y < height && src_x < width && src_y < height) {

Copy link
Member

@sev- sev- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants