SCUMM: GUI: Fix pre-v7 text rendering over GUI

This commit is contained in:
AndywinXp 2022-08-16 19:58:25 +02:00 committed by athrxx
parent 194555c3a7
commit 025d25a1f1
3 changed files with 92 additions and 8 deletions

View file

@ -1255,7 +1255,8 @@ void ScummEngine::restoreCharsetBg() {
_nextLeft = _string[0].xpos;
_nextTop = _string[0].ypos + _screenTop;
if (_charset->_hasMask) {
if (_charset->_hasMask || _postGUICharMask) {
_postGUICharMask = false;
_charset->_hasMask = false;
_charset->_str.left = -1;
_charset->_left = -1;

View file

@ -103,6 +103,12 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
convertMessageToString((const byte *)getGUIString(gsYesKey), (byte *)localizedY, sizeof(localizedY));
}
// Backup the text surface...
if (_game.version < 7) {
saveTextSurfacePreGUI();
restoreCharsetBg();
}
// Pause the engine
PauseToken pt = pauseEngine();
@ -209,6 +215,12 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
clearBanner();
}
// Restore the text surface...
if (_game.version < 7) {
restoreTextSurfacePostGUI();
_completeScreenRedraw = true;
}
// Finally, resume the engine, clear the input state, and restore the charset.
pt.clear();
clearClickedStatus();
@ -928,6 +940,50 @@ int ScummEngine::getBannerColor(int bannerId) {
return (int)arrAddr[bannerId];
}
void ScummEngine::saveTextSurfacePreGUI() {
if (_game.version < 4 || _game.version > 6)
return;
_tempTextSurface = (byte *)malloc(_textSurface.w * _textSurface.h * sizeof(byte));
int x, y;
uint32 curPix;
for (int i = 0; i < _textSurface.h; i++) {
for (int j = 0; j < _textSurface.w; j++) {
x = j;
y = i;
curPix = _textSurface.getPixel(x, y);
_tempTextSurface[j + i * _textSurface.w] = curPix;
if (curPix != 0xFD)
_virtscr[kMainVirtScreen].setPixel(_virtscr[kMainVirtScreen].xstart + x, y, curPix);
}
}
}
void ScummEngine::restoreTextSurfacePostGUI() {
if (_game.version < 4 || _game.version > 6)
return;
int x, y;
uint32 curPix;
for (int i = 0; i < _textSurface.h; i++) {
for (int j = 0; j < _textSurface.w; j++) {
x = j;
y = i;
curPix = _tempTextSurface[j + i * _textSurface.w];
_textSurface.setPixel(x, y, curPix);
}
}
// Signal the restoreCharsetBg() function that there's text
// on the text surface, so it gets deleted the next time another
// text is displayed...
_postGUICharMask = true;
free(_tempTextSurface);
_tempTextSurface = nullptr;
}
void ScummEngine::toggleVoiceMode() {
if (VAR_VOICE_MODE != 0xFF) {
VAR(VAR_VOICE_MODE) = (VAR(VAR_VOICE_MODE) != 1) ? 1 : 0;
@ -1069,13 +1125,15 @@ bool ScummEngine::canWriteGame(int slotId) {
}
bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicked, bool &rightMsClicked) {
bool hasLoadedState = false;
while (true) {
waitForTimer(1);
waitForBannerInput(-1, ks, leftMsClicked, rightMsClicked);
rightMsClicked = false;
if (ks.keycode == Common::KEYCODE_RETURN) {
clearClickedStatus();
executeMainMenuOperation(GUI_CTRL_OK_BUTTON, -1);
executeMainMenuOperation(GUI_CTRL_OK_BUTTON, -1, hasLoadedState);
return true;
} else if (leftMsClicked) {
clearClickedStatus();
@ -1153,6 +1211,7 @@ void ScummEngine::showMainMenu() {
bool leftMsClicked = false, rightMsClicked = false;
int clickedControl = -1;
int curMouseX, curMouseY;
bool hasLoadedState = false;
Common::KeyState ks;
@ -1171,6 +1230,19 @@ void ScummEngine::showMainMenu() {
_saveSound = 1;
setShake(0);
if (_game.version < 7) {
// Below version 7, we draw texts on a separate surface which is then composited
// on top of the main one during ScummEngine::drawDirtyScreenParts().
// This results in texts overlapping on top of the menu; let's simulate the end result
// of the original by copying the text surface over the main one just before showing
// the menu...
saveTextSurfacePreGUI();
// V6 games should call for stopTalk() instead, but that's a bit too drastic;
// this ensures that we can at least hear the speech after the menu is closed.
restoreCharsetBg();
}
_menuPage = GUI_PAGE_MAIN;
setUpMainMenuControls();
drawMainMenuControls();
@ -1226,7 +1298,7 @@ void ScummEngine::showMainMenu() {
drawInternalGUIControl(clickedControl, 0);
// Execute the operation pertaining the clicked control
if (executeMainMenuOperation(clickedControl, curMouseX))
if (executeMainMenuOperation(clickedControl, curMouseX, hasLoadedState))
break;
}
} else {
@ -1240,7 +1312,7 @@ void ScummEngine::showMainMenu() {
_system->updateScreen();
if (_menuPage == GUI_PAGE_LOAD) {
if (executeMainMenuOperation(GUI_CTRL_OK_BUTTON, curMouseX))
if (executeMainMenuOperation(GUI_CTRL_OK_BUTTON, curMouseX, hasLoadedState))
break;
}
}
@ -1282,12 +1354,15 @@ void ScummEngine::showMainMenu() {
if (_game.version == 7)
CHARSET_1();
if (_game.version < 7 && !hasLoadedState && !_quitByButton)
restoreTextSurfacePostGUI();
// Resume the engine
pt.clear();
clearClickedStatus();
}
bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedState) {
char saveScreenTitle[512];
char formattedString[512];
@ -1312,7 +1387,6 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
return true;
case GUI_CTRL_QUIT_BUTTON:
queryQuit();
_quitByButton = shouldQuit();
return true;
case GUI_CTRL_OK_BUTTON:
if (_menuPage == GUI_PAGE_SAVE) {
@ -1386,7 +1460,13 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
return true;
}
if (_game.version < 7) {
_postGUICharMask = true;
}
if (loadState(_mainMenuSavegameLabel + _curDisplayedSaveSlotPage * 9, false)) {
hasLoadedState = true;
if (!_spooledMusicIsToBeEnabled)
_imuseDigital->diMUSEDisableSpooledMusic();

View file

@ -635,6 +635,8 @@ protected:
int _spooledMusicIsToBeEnabled = 1;
int _saveScriptParam = 0;
Graphics::Surface _savegameThumbnail;
byte *_tempTextSurface;
bool _postGUICharMask = false;
// Saved cursor pre and post GUI
byte *_curGrabbedCursor = nullptr;
@ -681,14 +683,15 @@ protected:
void drawMainMenuControls();
void updateMainMenuControls();
void drawMainMenuTitle(const char *title);
bool executeMainMenuOperation(int op, int mouseX);
bool executeMainMenuOperation(int op, int mouseX, bool &hasLoadedState);
bool shouldHighlightLabelAndWait(int clickedControl);
void fillSavegameLabels();
bool canWriteGame(int slotId);
bool userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicked, bool &rightMsClicked);
void saveCursorPreMenu();
void restoreCursorPostMenu();
void saveTextSurfacePreGUI();
void restoreTextSurfacePostGUI();
public:
char displayMessage(const char *altButton, const char *message, ...) GCC_PRINTF(3, 4);