[Scummvm-git-logs] scummvm master -> ca527c8390022f54bf3863c4819d5ec1627f166d
bluegr
noreply at scummvm.org
Sat May 21 19:44:11 UTC 2022
This automated email contains information about 19 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
9fc868c7ed SCUMM: Implement quarter frame precision timing
95894ae9fe SCUMM: Implement accurate PIT timings for DOS versions
caae9399f5 SCUMM: Add PIT behavior for ZAK v1
9cf60930b9 SCUMM: Fix the timings update for the script variable
6bc2df1709 SCUMM: Correctly notify the music timer of the current ticks
e42ad88690 SCUMM: Implement original CD Audio timing handling
ecdbc25624 SCUMM: Properly reset CD Audio timers
f3eee39c9d SCUMM: Properly implement speech timer for v5-7 talkie games
b90609a95a SCUMM: Clean-up transitionEffect()
23afa3bb88 SCUMM: WIP rework for dissolveEffect()
6b838fd53a SCUMM: GFX: Update comments and kPictureDelay
6eef97375e SCUMM: GFX: Add clarificatory comment to scrollEffect()
9d236fa13b SCUMM: GFX: Finish implementation for dissolveEffect()
aa8c5285eb SCUMM: Fix comment
38ac6fbadc SCUMM: GFX: Fix bool comparison
07eafca398 SCUMM: INSANE: Set correct video framerate
2d12acec5a SCUMM: Add v7 quirk to IsMouthSyncOff()
ebb3f2a842 SCUMM: Implement Amiga timings
ca527c8390 SCUMM: Implement a better approximation of some Amiga quirks
Commit: 9fc868c7ed15cefd2a241d7a9a99fcd74b5c377a
https://github.com/scummvm/scummvm/commit/9fc868c7ed15cefd2a241d7a9a99fcd74b5c377a
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Implement quarter frame precision timing
Changed paths:
engines/scumm/gfx.cpp
engines/scumm/scumm.cpp
engines/scumm/scumm.h
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index cf0ab5c0cb1..423c694aa98 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -66,8 +66,7 @@ struct StripTable {
enum {
kScrolltime = 500, // ms scrolling is supposed to take
- kPictureDelay = 20,
- kFadeDelay = 4 // 1/4th of a jiffie
+ kPictureDelay = 5
};
#define NUM_SHAKE_POSITIONS 8
@@ -3920,7 +3919,7 @@ void ScummEngine::transitionEffect(int a) {
int bottom;
int l, t, r, b;
const int height = MIN((int)_virtscr[kMainVirtScreen].h, _screenHeight);
- const int delay = (VAR_FADE_DELAY != 0xFF) ? VAR(VAR_FADE_DELAY) * kFadeDelay : kPictureDelay;
+ const int delay = (VAR_FADE_DELAY != 0xFF) ? VAR(VAR_FADE_DELAY) : kPictureDelay;
for (i = 0; i < 16; i++) {
delta[i] = transitionEffects[a].deltaTable[i];
@@ -3979,7 +3978,7 @@ void ScummEngine::transitionEffect(int a) {
void ScummEngine::dissolveEffect(int width, int height) {
VirtScreen *vs = &_virtscr[kMainVirtScreen];
int *offsets;
- int blits_before_refresh, blits;
+ int blitsBeforeRefresh, blits;
int x, y;
int w, h;
int i;
@@ -4049,7 +4048,7 @@ void ScummEngine::dissolveEffect(int width, int height) {
// but might still need some tuning.
blits = 0;
- blits_before_refresh = (3 * w * h) / 25;
+ blitsBeforeRefresh = (3 * w * h) / 25; // TODO: Check
// Speed up the effect for CD Loom since it uses it so often. I don't
// think the original had any delay at all, so on modern hardware it
@@ -4072,17 +4071,17 @@ void ScummEngine::dissolveEffect(int width, int height) {
_system->copyRectToScreen(vs->getPixels(x, y), vs->pitch, x, y + vs->topline, width, height);
- if (++blits >= blits_before_refresh) {
+ if (++blits >= blitsBeforeRefresh) {
blits = 0;
- waitForTimer(30);
+ waitForTimer(4);
}
}
- free(offsets);
-
if (blits != 0) {
- waitForTimer(30);
+ waitForTimer(4);
}
+
+ free(offsets);
}
void ScummEngine::scrollEffect(int dir) {
@@ -4097,7 +4096,7 @@ void ScummEngine::scrollEffect(int dir) {
int x, y;
int step;
- const int delay = (VAR_FADE_DELAY != 0xFF) ? VAR(VAR_FADE_DELAY) * kFadeDelay : kPictureDelay;
+ const int delay = (VAR_FADE_DELAY != 0xFF) ? VAR(VAR_FADE_DELAY) : kPictureDelay;
if ((dir == 0) || (dir == 1))
step = vs->h;
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index db0ac280b8d..c64f3e6a662 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2101,6 +2101,7 @@ Common::Error ScummEngine::go() {
_rnd.getRandomNumber(2);
// Notify the script about how much time has passed, in ticks (60 ticks per second)
+ uint32 diff = _system->getMillis() - _lastWaitTime;
if (VAR_TIMER != 0xFF)
VAR(VAR_TIMER) = diff * 60 / 1000;
if (VAR_TIMER_TOTAL != 0xFF)
@@ -2142,19 +2143,16 @@ Common::Error ScummEngine::go() {
delta = 6;
}
- // Wait and start the stop watch at the time the wait is assumed
+ // Wait, start and stop the stop watch at the time the wait is assumed
// to end. There is no guarantee that the wait is that exact,
// but this way if it overshoots that time will count as part
// of the main loop.
- diff = waitForTimer(delta * 1000 / 60 - diff);
+ waitForTimer(delta * 4);
// Run the main loop
scummLoop(delta);
- // Halt the stop watch and compute how much time this iteration took.
- diff = _system->getMillis() - diff;
-
if (shouldQuit()) {
// TODO: Maybe perform an autosave on exit?
runQuitScript();
@@ -2164,17 +2162,19 @@ Common::Error ScummEngine::go() {
return Common::kNoError;
}
-int ScummEngine::waitForTimer(int msec_delay) {
- uint32 end_time;
+void ScummEngine::waitForTimer(int quarterFrames) {
+ uint32 endTime, cur;
+ uint32 msecDelay = getIntegralTime(quarterFrames * (1000 / 60.0) / 4);
if (_fastMode & 2)
- msec_delay = 0;
+ msecDelay = 0;
else if (_fastMode & 1)
- msec_delay = 10;
-
- uint32 cur = _system->getMillis();;
+ msecDelay = 10;
- end_time = cur + msec_delay;
+ cur = _system->getMillis();
+ uint32 diff = cur - _lastWaitTime;
+ msecDelay = (msecDelay > diff) ? msecDelay - diff : 0;
+ endTime = cur + msecDelay;
while (!shouldQuit()) {
_sound->updateCD(); // Loop CD Audio if needed
@@ -2196,20 +2196,31 @@ int ScummEngine::waitForTimer(int msec_delay) {
_refreshDuration[_refreshArrayPos] = (int)(cur - screenUpdateTimerStart);
_refreshArrayPos = (_refreshArrayPos + 1) % ARRAYSIZE(_refreshDuration);
#endif
- if (cur >= end_time)
+ if (cur >= endTime)
break;
- _system->delayMillis(MIN<uint32>(10, end_time - cur));
+ _system->delayMillis(MIN<uint32>(10, endTime - cur));
}
- // Return the expected end time, which may be different from the actual
- // time. This helps the main loop maintain consistent timing.
+ // Set the last wait time as the expected end time, which may be different
+ // from the actual time. This helps the main loop maintain consistent timing.
//
// If it's lagging too far behind, we probably resumed from pausing, or
// the process was suspended, or any such thing. We probably can't
// sensibly detect all of them from within ScummVM, so in that case we
// simply return the current time to catch up.
- return (cur > end_time + 50) ? cur : end_time;
+ _lastWaitTime = (cur > endTime + 50) ? cur : endTime;
+}
+
+uint32 ScummEngine::getIntegralTime(double fMsecs) {
+ double msecIntPart;
+ _msecFractParts += modf(fMsecs, &msecIntPart);
+ if (_msecFractParts >= 1) {
+ _msecFractParts--;
+ msecIntPart++;
+ }
+
+ return msecIntPart;
}
void ScummEngine_v0::scummLoop(int delta) {
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index fe1973b0686..40bbdb359e3 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -383,7 +383,17 @@ public:
protected:
virtual void parseEvent(Common::Event event);
- int waitForTimer(int msec_delay);
+ void waitForTimer(int quarterFrames);
+ uint32 _lastWaitTime;
+
+ /**
+ * Represents fractional milliseconds by decomposing the passed
+ * value into integral and fractional parts, then incrementing the
+ * integer part as needed on subsequent function calls.
+ */
+ uint32 getIntegralTime(double fMsecs);
+ double _msecFractParts;
+
virtual void processInput();
virtual void processKeyboard(Common::KeyState lastKeyHit);
virtual void clearClickedStatus();
Commit: 95894ae9fe06bb073d1f9f4c28c2a7f887072da8
https://github.com/scummvm/scummvm/commit/95894ae9fe06bb073d1f9f4c28c2a7f887072da8
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Implement accurate PIT timings for DOS versions
Changed paths:
engines/scumm/gfx.cpp
engines/scumm/scumm.cpp
engines/scumm/scumm.h
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 423c694aa98..17f58251247 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -65,7 +65,6 @@ struct StripTable {
};
enum {
- kScrolltime = 500, // ms scrolling is supposed to take
kPictureDelay = 5
};
@@ -4095,16 +4094,9 @@ void ScummEngine::scrollEffect(int dir) {
VirtScreen *vs = &_virtscr[kMainVirtScreen];
int x, y;
- int step;
+ const int step = 8;
const int delay = (VAR_FADE_DELAY != 0xFF) ? VAR(VAR_FADE_DELAY) : kPictureDelay;
- if ((dir == 0) || (dir == 1))
- step = vs->h;
- else
- step = vs->w;
-
- step = (step * delay) / kScrolltime;
-
byte *src;
int m = _textSurfaceMultiplier;
int vsPitch = vs->pitch;
@@ -4227,7 +4219,7 @@ void ScummEngine::updateScreenShakeEffect() {
// but inside each respective ims driver during the driver load/init process. The screen shakes update every 8 ticks.
// LOOM uses either 236.696 Hz at 8 ticks delay or 473.297 Hz at 16 ticks delay, depending on the sound card selection.
// The outcome is the same...
- _shakeTickCounter += ((1000000000 / _shakeTimerRate) * 8);
+ _shakeTickCounter += ((1000000 / _shakeTimerRate) * 8);
_shakeNextTick += (_shakeTickCounter / 1000);
_shakeTickCounter %= 1000;
}
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index c64f3e6a662..b500053e18c 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -106,9 +106,9 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_game(dr.game),
_filenamePattern(dr.fp),
_language(dr.language),
- _rnd("scumm"),
- _shakeTimerRate(dr.game.version <= 3 ? 236696 : 291304)
+ _rnd("scumm")
{
+
#ifdef USE_RGB_COLOR
if (_game.features & GF_16BIT_COLOR) {
if (_game.platform == Common::kPlatformPCEngine)
@@ -152,6 +152,9 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
for (uint i = 0; i < ARRAYSIZE(_virtscr); i++) {
_virtscr[i].clear();
}
+
+ setTimerAndShakeFrequency();
+
camera.reset();
memset(_colorCycle, 0, sizeof(_colorCycle));
memset(_colorUsedByCycle, 0, sizeof(_colorUsedByCycle));
@@ -2093,8 +2096,6 @@ Common::Error ScummEngine::go() {
_saveLoadFlag = 0;
}
- int diff = 0; // Duration of one loop iteration
-
while (!shouldQuit()) {
// Randomize the PRNG by calling it at regular intervals. This ensures
// that it will be in a different state each time you run the program.
@@ -2135,12 +2136,13 @@ Common::Error ScummEngine::go() {
delta += ((ScummEngine_v0 *)this)->DelayCalculateDelta();
}
- // WORKAROUND: walking speed in the original v1 interpreter
- // is sometimes slower (e.g. during scrolling) than in ScummVM.
- // This is important for the door-closing action in the dungeon,
- // otherwise (delta < 6) a single kid is able to escape.
- if (_game.version == 1 && isScriptRunning(137)) {
- delta = 6;
+ // In MANIAC V1, the workings of the wait loop will increment the
+ // timer past the comparison, producing a longer wait loop than
+ // expected. The timer resolution is lower than the frame-time
+ // derived from it, i.e., one tick represents three frames. We need
+ // to round up VAR_TIMER_NEXT to the nearest multiple of three.
+ if (_game.id == GID_MANIAC && _game.version == 1) {
+ delta = ceil(delta / 3.0) * 3;
}
// Wait, start and stop the stop watch at the time the wait is assumed
@@ -2164,7 +2166,7 @@ Common::Error ScummEngine::go() {
void ScummEngine::waitForTimer(int quarterFrames) {
uint32 endTime, cur;
- uint32 msecDelay = getIntegralTime(quarterFrames * (1000 / 60.0) / 4);
+ uint32 msecDelay = getIntegralTime(quarterFrames * (1000 / _timerFrequency));
if (_fastMode & 2)
msecDelay = 0;
@@ -2223,6 +2225,45 @@ uint32 ScummEngine::getIntegralTime(double fMsecs) {
return msecIntPart;
}
+void ScummEngine::setTimerAndShakeFrequency() {
+ _shakeTimerRate = _timerFrequency = 240.0;
+
+ if (_game.platform == Common::kPlatformDOS || _game.platform == Common::kPlatformUnknown) {
+ switch (_game.version) {
+ case 1:
+ if (_game.id == GID_MANIAC) {
+ // In MANIAC V1, one tick represents three frames,
+ // i.e., 12 quarter-frames.
+ _shakeTimerRate = _timerFrequency = PIT_BASE_FREQUENCY / PIT_V1_DIVISOR * 12;
+ }
+ break;
+ case 2:
+ case 3:
+ case 4:
+ _shakeTimerRate = _timerFrequency = PIT_BASE_FREQUENCY / PIT_V2_4_DIVISOR;
+ break;
+ case 5:
+ _shakeTimerRate = _timerFrequency = PIT_BASE_FREQUENCY / PIT_V5_6_ORCHESTRATOR_DIVISOR;
+ _timerFrequency *= PIT_V5_6_SUBTIMER_INC / PIT_V5_SUBTIMER_THRESH;
+ break;
+ case 6:
+ _shakeTimerRate = _timerFrequency = PIT_BASE_FREQUENCY / PIT_V5_6_ORCHESTRATOR_DIVISOR;
+ if (_game.id == GID_TENTACLE) {
+ _timerFrequency *= PIT_V5_6_SUBTIMER_INC / PIT_V6_DOTT_SUBTIMER_THRESH;
+ } else {
+ _timerFrequency *= PIT_V5_6_SUBTIMER_INC / PIT_V6_SAMNMAX_SUBTIMER_THRESH;
+ }
+ break;
+ case 7:
+ _shakeTimerRate = _timerFrequency = PIT_BASE_FREQUENCY / PIT_V7_ORCHESTRATOR_DIVISOR;
+ _timerFrequency *= PIT_V7_SUBTIMER_INC / PIT_V7_SUBTIMER_THRESH;
+ break;
+ default:
+ _shakeTimerRate = _timerFrequency = 240.0;
+ }
+ }
+}
+
void ScummEngine_v0::scummLoop(int delta) {
VAR(VAR_IS_SOUND_RUNNING) = (_sound->_lastSound && _sound->isSoundRunning(_sound->_lastSound) != 0);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 40bbdb359e3..187aaaa8411 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -280,6 +280,58 @@ typedef uint16 ResId;
class ResourceManager;
+/**
+ * DOS Programmable Interrupt Timer constants.
+ *
+ * The SCUMM engine (v1-v7, DOS) timer ticks are based on the jiffy unit (roughly 60Hz).
+ * Well, if we want to be pedantic about it, it operates on quarter jiffies (240Hz),
+ * a rate at which several screen effects are updated; but still, this value is divided
+ * by 4 in the main game loop in order for it to operate on whole jiffies.
+ * In order to obtain this behavior, the PIT is programmed to operate at roughly 240Hz,
+ * though these timings change from version to version (or game by game, for v6).
+ *
+ * Glossary:
+ * - Base frequency: this is the frequency at which the Intel 8253/54 PIT
+ * operates, namely obtained with the formula 105/88, which
+ * yields 1.193181818... MHz. We are storing it in Hz;
+ *
+ * - Divisor: the base frequency in DOS is not used as-is, but it is instead
+ * divided by a customizable divisor which can range between
+ * 0 and (2^16-1), where 0 is a shortcut for 2^16. This operation
+ * yields the custom frequency at which the custom assigned interrupt
+ * gets called (hence "Programmable");
+ *
+ * - Orchestrator: starting from SCUMM v5, games started using iMUSE, and apparently
+ * needed a more precise timing handling; this led to the introduction
+ * of a main orchestrator timer (which then handled the execution of
+ other sub-timers), whose divisor (4096) was set up in the IMS
+ * drivers up until v7, in which the divisor (3977) was set up in the
+ * executable as a part of the INSANE orchestration;
+ *
+ * - Sub-timer: custom made timers, operating under an orchestrator; in the macros
+ * below, "INC" refers to the increment of an accumulator which gets
+ * updated at each iteration of the orchestrator interrupt; "THRESH"
+ * refers to a threshold value of the aforementioned accumulator,
+ * beyond which the accumulator is decremented by the threshold value,
+ * and the interrupt of the sub-timer gets executed (e.g. the values
+ * below mainly refer to the interrupt which increments the SCUMM
+ * quarter frame counter.
+ *
+ * All the values below are presented as doubles, so to safely yield fractional results.
+ */
+
+#define PIT_BASE_FREQUENCY 1193182.0 // In Hz
+#define PIT_V1_DIVISOR 65536.0
+#define PIT_V2_4_DIVISOR 5041.0
+#define PIT_V5_6_ORCHESTRATOR_DIVISOR 4096.0
+#define PIT_V5_6_SUBTIMER_INC 3433.0
+#define PIT_V5_SUBTIMER_THRESH 4167.0
+#define PIT_V6_SAMNMAX_SUBTIMER_THRESH 4167.0
+#define PIT_V6_DOTT_SUBTIMER_THRESH 4237.0
+#define PIT_V7_ORCHESTRATOR_DIVISOR 3977.0
+#define PIT_V7_SUBTIMER_INC 3977.0
+#define PIT_V7_SUBTIMER_THRESH 4971.0
+
/**
* Base class for all SCUMM engines.
*/
@@ -386,6 +438,8 @@ protected:
void waitForTimer(int quarterFrames);
uint32 _lastWaitTime;
+ void setTimerAndShakeFrequency();
+
/**
* Represents fractional milliseconds by decomposing the passed
* value into integral and fractional parts, then incrementing the
@@ -1018,7 +1072,8 @@ protected:
uint _shakeFrame = 0;
uint32 _shakeNextTick = 0;
uint32 _shakeTickCounter = 0;
- const uint32 _shakeTimerRate;
+ double _shakeTimerRate;
+ double _timerFrequency;
void setShake(int mode);
Commit: caae9399f5c5c970d2f89cef097852ae5137eefa
https://github.com/scummvm/scummvm/commit/caae9399f5c5c970d2f89cef097852ae5137eefa
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Add PIT behavior for ZAK v1
Changed paths:
engines/scumm/scumm.cpp
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index b500053e18c..c677218805f 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2235,6 +2235,8 @@ void ScummEngine::setTimerAndShakeFrequency() {
// In MANIAC V1, one tick represents three frames,
// i.e., 12 quarter-frames.
_shakeTimerRate = _timerFrequency = PIT_BASE_FREQUENCY / PIT_V1_DIVISOR * 12;
+ } else {
+ _shakeTimerRate = _timerFrequency = PIT_BASE_FREQUENCY / PIT_V2_4_DIVISOR;
}
break;
case 2:
Commit: 9cf60930b9639b349d973edbb91e5bfa728f8f67
https://github.com/scummvm/scummvm/commit/9cf60930b9639b349d973edbb91e5bfa728f8f67
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Fix the timings update for the script variable
This fixes music/game sync issues at the end of DOTT intro (before the main theme)
Changed paths:
engines/scumm/gfx.cpp
engines/scumm/scumm.cpp
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 17f58251247..d36eea2db57 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -4053,7 +4053,7 @@ void ScummEngine::dissolveEffect(int width, int height) {
// think the original had any delay at all, so on modern hardware it
// wasn't even noticeable.
if (_game.id == GID_LOOM && (_game.version == 4))
- blits_before_refresh *= 2;
+ blitsBeforeRefresh *= 2;
for (i = 0; i < w * h; i++) {
x = offsets[i] % vs->pitch;
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index c677218805f..082cca71f16 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2101,12 +2101,13 @@ Common::Error ScummEngine::go() {
// that it will be in a different state each time you run the program.
_rnd.getRandomNumber(2);
- // Notify the script about how much time has passed, in ticks (60 ticks per second)
+ // Notify the script about how much time has passed, in jiffies
+ // (the timing varies depending on the SCUMM version and the game)
uint32 diff = _system->getMillis() - _lastWaitTime;
if (VAR_TIMER != 0xFF)
- VAR(VAR_TIMER) = diff * 60 / 1000;
+ VAR(VAR_TIMER) = diff * (_timerFrequency / 4) / 1000;
if (VAR_TIMER_TOTAL != 0xFF)
- VAR(VAR_TIMER_TOTAL) += diff * 60 / 1000;
+ VAR(VAR_TIMER_TOTAL) += diff * (_timerFrequency / 4) / 1000;
// Determine how long to wait before the next loop iteration should start
int delta = (VAR_TIMER_NEXT != 0xFF) ? VAR(VAR_TIMER_NEXT) : 4;
Commit: 6bc2df17094186e4c23fb64e46685694d37c8563
https://github.com/scummvm/scummvm/commit/6bc2df17094186e4c23fb64e46685694d37c8563
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Correctly notify the music timer of the current ticks
Changed paths:
engines/scumm/scumm.cpp
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 082cca71f16..131994ac417 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2317,10 +2317,10 @@ void ScummEngine::scummLoop(int delta) {
} else if (VAR_MUSIC_TIMER != 0xFF) {
if (_sound->useReplacementAudioTracks() && _sound->getCurrentCDSound()) {
_sound->updateMusicTimer();
- VAR(VAR_MUSIC_TIMER) = _sound->getMusicTimer();
+ VAR(VAR_MUSIC_TIMER) = _sound->getMusicTimer() * _timerFrequency / 240.0;
} else if (_musicEngine) {
// The music engine generates the timer data for us.
- VAR(VAR_MUSIC_TIMER) = _musicEngine->getMusicTimer();
+ VAR(VAR_MUSIC_TIMER) = _musicEngine->getMusicTimer() * _timerFrequency / 240.0;
}
}
Commit: e42ad8869092273b3e4e0fb00542e5a3fdd7c7c7
https://github.com/scummvm/scummvm/commit/e42ad8869092273b3e4e0fb00542e5a3fdd7c7c7
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Implement original CD Audio timing handling
Changed paths:
engines/scumm/scumm.cpp
engines/scumm/scumm.h
engines/scumm/sound.cpp
engines/scumm/sound.h
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 131994ac417..39347740aef 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2267,6 +2267,10 @@ void ScummEngine::setTimerAndShakeFrequency() {
}
}
+double ScummEngine::getTimerFrequency() {
+ return _timerFrequency;
+}
+
void ScummEngine_v0::scummLoop(int delta) {
VAR(VAR_IS_SOUND_RUNNING) = (_sound->_lastSound && _sound->isSoundRunning(_sound->_lastSound) != 0);
@@ -2313,7 +2317,7 @@ void ScummEngine::scummLoop(int delta) {
scummLoop_updateScummVars();
if (_game.features & GF_AUDIOTRACKS) {
- // Covered automatically by the Sound class
+ VAR(VAR_MUSIC_TIMER) = _sound->getCDMusicTimer();
} else if (VAR_MUSIC_TIMER != 0xFF) {
if (_sound->useReplacementAudioTracks() && _sound->getCurrentCDSound()) {
_sound->updateMusicTimer();
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 187aaaa8411..48efbf5d58f 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -1067,6 +1067,9 @@ protected:
void updateScreenShakeEffect();
+public:
+ double getTimerFrequency();
+
protected:
bool _shakeEnabled = false;
uint _shakeFrame = 0;
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 86fb717c787..f8479b3c78b 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -62,6 +62,8 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer, bool useReplacementAudioT
_replacementTrackStartTime(0),
_replacementTrackPauseTime(0),
_musicTimer(0),
+ _cdMusicTimerMod(0),
+ _cdMusicTimer(0),
_soundQuePos(0),
_soundQue2Pos(0),
_sfxFilename(),
@@ -1339,42 +1341,38 @@ bool Sound::isSfxFinished() const {
return !_mixer->hasActiveChannelOfType(Audio::Mixer::kSFXSoundType);
}
-// We use a real timer in an attempt to get better sync with CD tracks. This is
-// necessary for games like Loom CD.
-
-static void cd_timer_handler(void *refCon) {
- ScummEngine *scumm = (ScummEngine *)refCon;
+static void cdTimerHandler(void *refCon) {
+ Sound *snd = (Sound *)refCon;
// FIXME: Turn off the timer when it's no longer needed. In theory, it
// should be possible to check with pollCD(), but since CD sound isn't
// properly restarted when reloading a saved game, I don't dare to.
-
- scumm->VAR(scumm->VAR_MUSIC_TIMER) += 6;
+ if ((snd->_cdMusicTimerMod++ & 3) == 0) {
+ snd->_cdMusicTimer++;
+ }
}
void Sound::startCDTimer() {
if (_useReplacementAudioTracks)
return;
- // This timer interval is based on two scenes: The Monkey Island 1
- // intro, and the scene in Loom CD where Chaos appears. In both cases
- // the game plays the scene as two separate sounds, even though both
- // halves are right next to each other in the CD track. Probably so
- // that you can hit Escape to skip the first half.
+ // This CD timer implementation strictly follows the original interpreters for
+ // Monkey Island 1 CD and Loom CD: it works by incrementing _cdMusicTimerMod and _cdMusicTimer
+ // at each quarter frame (see ScummEngine::setTimerAndShakeFrequency() for what the exact
+ // frequency rate is for the particular game and engine version being ran).
//
- // Make it too low, and the Monkey Island theme will be cut short. Make
- // it too high, and there will be a nasty "hiccup" just as Chaos
- // appears.
-
- _vm->getTimerManager()->removeTimerProc(&cd_timer_handler);
- _vm->getTimerManager()->installTimerProc(&cd_timer_handler, 100700, _vm, "scummCDtimer");
+ // Again as per the interpreters, VAR_MUSIC_TIMER is then updated inside the SCUMM main loop.
+ _vm->getTimerManager()->removeTimerProc(&cdTimerHandler);
+ _vm->getTimerManager()->installTimerProc(&cdTimerHandler, 1000000 / _vm->getTimerFrequency(), this, "scummCDtimer");
}
void Sound::stopCDTimer() {
if (_useReplacementAudioTracks)
return;
- _vm->getTimerManager()->removeTimerProc(&cd_timer_handler);
+ _cdMusicTimerMod = 0;
+ _cdMusicTimer = 0;
+ _vm->getTimerManager()->removeTimerProc(&cdTimerHandler);
}
void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) {
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index 21e00e8e3bb..732871f287b 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -112,6 +112,8 @@ public:
bool _soundsPaused;
byte _sfxMode;
uint _lastSound;
+ uint32 _cdMusicTimerMod;
+ uint32 _cdMusicTimer;
MidiDriverFlags _musicType;
@@ -154,6 +156,7 @@ public:
bool useReplacementAudioTracks() const { return _useReplacementAudioTracks; }
void updateMusicTimer();
int getMusicTimer() const { return _musicTimer; }
+ int getCDMusicTimer() const { return _cdMusicTimer; }
void saveLoadWithSerializer(Common::Serializer &ser) override;
void restoreAfterLoad();
Commit: ecdbc256243116dd2d351f061ab1b8eb08742e0a
https://github.com/scummvm/scummvm/commit/ecdbc256243116dd2d351f061ab1b8eb08742e0a
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Properly reset CD Audio timers
Changed paths:
engines/scumm/sound.cpp
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index f8479b3c78b..96f7736afc3 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -1370,14 +1370,14 @@ void Sound::stopCDTimer() {
if (_useReplacementAudioTracks)
return;
- _cdMusicTimerMod = 0;
- _cdMusicTimer = 0;
_vm->getTimerManager()->removeTimerProc(&cdTimerHandler);
}
void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) {
// Reset the music timer variable at the start of a new track
_vm->VAR(_vm->VAR_MUSIC_TIMER) = 0;
+ _cdMusicTimerMod = 0;
+ _cdMusicTimer = 0;
// Play it
if (!_soundsPaused)
Commit: f3eee39c9d4d64bdbb17349795064bd9ea887eac
https://github.com/scummvm/scummvm/commit/f3eee39c9d4d64bdbb17349795064bd9ea887eac
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Properly implement speech timer for v5-7 talkie games
Changed paths:
engines/scumm/sound.cpp
engines/scumm/sound.h
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 96f7736afc3..9ed8850db3a 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -64,6 +64,7 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer, bool useReplacementAudioT
_musicTimer(0),
_cdMusicTimerMod(0),
_cdMusicTimer(0),
+ _speechTimerMod(0),
_soundQuePos(0),
_soundQue2Pos(0),
_sfxFilename(),
@@ -105,6 +106,13 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer, bool useReplacementAudioT
_loomSteamCDAudioHandle = new Audio::SoundHandle();
_talkChannelHandle = new Audio::SoundHandle();
+
+ // This timer targets every talkie game, except for LOOM CD
+ // which is handled differently, and except for COMI which
+ // handles lipsync within Digital iMUSE.
+ if (_vm->_game.version >= 5 && _vm->_game.version <= 7) {
+ startSpeechTimer();
+ }
}
Sound::~Sound() {
@@ -113,6 +121,9 @@ Sound::~Sound() {
free(_offsetTable);
delete _loomSteamCDAudioHandle;
delete _talkChannelHandle;
+ if (_vm->_game.version >= 5 && _vm->_game.version <= 7) {
+ stopSpeechTimer();
+ }
}
bool Sound::isRolandLoom() const {
@@ -590,16 +601,17 @@ void Sound::processSfxQueues() {
if (_vm->_imuseDigital) {
finished = !isSoundRunning(kTalkSoundID);
+ if (_vm->_game.id == GID_CMI) {
#if defined(ENABLE_SCUMM_7_8)
- _curSoundPos = _vm->_imuseDigital->getSoundElapsedTimeInMs(kTalkSoundID) * 60 / 1000;
+ _curSoundPos = _vm->_imuseDigital->getSoundElapsedTimeInMs(kTalkSoundID) * 60 / 1000;
#endif
+ }
} else if (_vm->_game.heversion >= 60) {
finished = !isSoundRunning(1);
} else {
finished = !_mixer->isSoundHandleActive(*_talkChannelHandle);
- // calculate speech sound position simulating increment at 60FPS
- _curSoundPos = (_mixer->getSoundElapsedTime(*_talkChannelHandle) * 60) / 1000;
}
+
if ((uint) act < 0x80 && ((_vm->_game.version == 8) || (_vm->_game.version <= 7 && !_vm->_string[0].no_talk_anim))) {
a = _vm->derefActor(act, "processSfxQueues");
if (a->isInCurrentRoom()) {
@@ -692,7 +704,7 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle
_sfxMode |= mode;
if (_vm->_game.id == GID_DIG)
- _curSoundPos = 0;
+ resetSpeechTimer();
return;
} else if (_vm->_game.id == GID_DIG && (_vm->_game.features & GF_DEMO)) {
@@ -777,7 +789,7 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle
_mouthSyncTimes[i] = 0xFFFF;
_sfxMode |= mode;
- _curSoundPos = 0;
+ resetSpeechTimer();
_mouthSyncMode = true;
totalOffset = offset + b;
@@ -877,7 +889,7 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle
_mouthSyncTimes[i] = 0xFFFF;
_sfxMode |= mode;
- _curSoundPos = 0;
+ resetSpeechTimer();
_mouthSyncMode = true;
}
@@ -958,6 +970,7 @@ bool Sound::isMouthSyncOff(uint pos) {
uint j;
bool val = true;
uint16 *ms = _mouthSyncTimes;
+ uint delay = (_vm->_game.version == 6) ? 10 : 0;
if (_vm->_game.id == GID_DIG && !(_vm->_game.features & GF_DEMO)) {
pos = 1000 * pos / 60;
@@ -972,7 +985,7 @@ bool Sound::isMouthSyncOff(uint pos) {
_endOfMouthSync = true;
break;
}
- } while (pos > j);
+ } while (pos + delay > j);
return val;
}
@@ -1341,6 +1354,30 @@ bool Sound::isSfxFinished() const {
return !_mixer->hasActiveChannelOfType(Audio::Mixer::kSFXSoundType);
}
+void Sound::incrementSpeechTimer() {
+ if (!_soundsPaused)
+ _curSoundPos++;
+}
+
+void Sound::resetSpeechTimer() {
+ _curSoundPos = 0;
+}
+
+static void speechTimerHandler(void *refCon) {
+ Sound *snd = (Sound *)refCon;
+ if ((snd->_speechTimerMod++ & 3) == 0) {
+ snd->incrementSpeechTimer();
+ }
+}
+
+void Sound::startSpeechTimer() {
+ _vm->getTimerManager()->installTimerProc(&speechTimerHandler, 1000000 / _vm->getTimerFrequency(), this, "scummSpeechTimer");
+}
+
+void Sound::stopSpeechTimer() {
+ _vm->getTimerManager()->removeTimerProc(&speechTimerHandler);
+}
+
static void cdTimerHandler(void *refCon) {
Sound *snd = (Sound *)refCon;
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index 732871f287b..11474dd3d10 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -114,6 +114,7 @@ public:
uint _lastSound;
uint32 _cdMusicTimerMod;
uint32 _cdMusicTimer;
+ uint32 _speechTimerMod;
MidiDriverFlags _musicType;
@@ -140,6 +141,10 @@ public:
bool hasSfxFile() const;
ScummFile *restoreDiMUSESpeechFile(const char *fileName);
void extractSyncsFromDiMUSEMarker(const char *marker);
+ void incrementSpeechTimer();
+ void resetSpeechTimer();
+ void startSpeechTimer();
+ void stopSpeechTimer();
void startCDTimer();
void stopCDTimer();
Commit: b90609a95a4d358ddc82556ca21abfccc8a15ffd
https://github.com/scummvm/scummvm/commit/b90609a95a4d358ddc82556ca21abfccc8a15ffd
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Clean-up transitionEffect()
Changed paths:
engines/scumm/gfx.cpp
engines/scumm/scumm.h
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index d36eea2db57..1b119e7c915 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -65,6 +65,7 @@ struct StripTable {
};
enum {
+ kNoDelay = 0,
kPictureDelay = 5
};
@@ -3813,7 +3814,7 @@ void ScummEngine::fadeIn(int effect) {
transitionEffect(effect - 1);
break;
case 128:
- unkScreenEffect6();
+ dissolveEffectSelector();
break;
case 129:
break;
@@ -3875,7 +3876,7 @@ void ScummEngine::fadeOut(int effect) {
transitionEffect(effect - 1);
break;
case 128:
- unkScreenEffect6();
+ dissolveEffectSelector();
break;
case 129:
// Just blit screen 0 to the display (i.e. display will be black)
@@ -3912,13 +3913,31 @@ void ScummEngine::fadeOut(int effect) {
* @param a the transition effect to perform
*/
void ScummEngine::transitionEffect(int a) {
- int delta[16]; // Offset applied during each iteration
+ int delta[16]; // Offset applied during each iteration
int tab_2[16];
int i, j;
int bottom;
int l, t, r, b;
+ int delay, numOfIterations;
const int height = MIN((int)_virtscr[kMainVirtScreen].h, _screenHeight);
- const int delay = (VAR_FADE_DELAY != 0xFF) ? VAR(VAR_FADE_DELAY) : kPictureDelay;
+
+ if (VAR_FADE_DELAY == 0xFF) {
+ if (_game.version >= 2) {
+ delay = kPictureDelay;
+ } else {
+ delay = kNoDelay;
+ }
+ } else {
+ delay = VAR(VAR_FADE_DELAY);
+ }
+
+ // V3+ games have the number of iterations hardcoded; we also
+ // have that number hardcoded for MM NES, so let's target that too:
+ if (_game.version >= 3 || _game.platform == Common::kPlatformNES) {
+ numOfIterations = transitionEffects[a].numOfIterations;
+ } else {
+ numOfIterations = (a == 0 || a == 4) ? ceil((height / 8.0) / 2) : height / 8;
+ }
for (i = 0; i < 16; i++) {
delta[i] = transitionEffects[a].deltaTable[i];
@@ -3929,7 +3948,7 @@ void ScummEngine::transitionEffect(int a) {
}
bottom = height / 8;
- for (j = 0; j < transitionEffects[a].numOfIterations; j++) {
+ for (j = 0; j < numOfIterations; j++) {
for (i = 0; i < 4; i++) {
l = tab_2[i * 4];
t = tab_2[i * 4 + 1];
@@ -3960,9 +3979,11 @@ void ScummEngine::transitionEffect(int a) {
for (i = 0; i < 16; i++)
tab_2[i] += delta[i];
- // Draw the current state to the screen and wait a few secs so the
- // user can watch the effect taking place.
- waitForTimer(delay);
+ // Draw the current state to the screen and wait
+ // for the appropriate number of quarter frames
+ if (!_fastMode) {
+ waitForTimer(delay);
+ }
}
}
@@ -4118,7 +4139,6 @@ void ScummEngine::scrollEffect(int dir) {
vsPitch,
0, (vs->h - step) * m,
vs->w * m, step * m);
- _system->updateScreen();
}
waitForTimer(delay);
@@ -4141,7 +4161,6 @@ void ScummEngine::scrollEffect(int dir) {
vsPitch,
0, 0,
vs->w * m, step * m);
- _system->updateScreen();
}
waitForTimer(delay);
@@ -4159,7 +4178,6 @@ void ScummEngine::scrollEffect(int dir) {
vsPitch,
(vs->w - step) * m, 0,
step * m, vs->h * m);
- _system->updateScreen();
waitForTimer(delay);
x += step;
@@ -4176,7 +4194,6 @@ void ScummEngine::scrollEffect(int dir) {
vsPitch,
0, 0,
step, vs->h);
- _system->updateScreen();
waitForTimer(delay);
x += step;
@@ -4187,7 +4204,7 @@ void ScummEngine::scrollEffect(int dir) {
}
}
-void ScummEngine::unkScreenEffect6() {
+void ScummEngine::dissolveEffectSelector() {
// CD Loom (but not EGA Loom!) uses a more fine-grained dissolve
if (_game.id == GID_LOOM && _game.version == 4)
dissolveEffect(1, 1);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 48efbf5d58f..8fcba794ee9 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -1060,7 +1060,7 @@ protected:
void fadeOut(int effect);
void setScrollBuffer();
- void unkScreenEffect6();
+ void dissolveEffectSelector();
void transitionEffect(int a);
void dissolveEffect(int width, int height);
void scrollEffect(int dir);
Commit: 23afa3bb88d036718efe31b44ba9ebaa4a41247b
https://github.com/scummvm/scummvm/commit/23afa3bb88d036718efe31b44ba9ebaa4a41247b
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: WIP rework for dissolveEffect()
Changed paths:
engines/scumm/gfx.cpp
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 1b119e7c915..a7fd2aed399 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -4068,13 +4068,13 @@ void ScummEngine::dissolveEffect(int width, int height) {
// but might still need some tuning.
blits = 0;
- blitsBeforeRefresh = (3 * w * h) / 25; // TODO: Check
+ blitsBeforeRefresh = (w * h) / 8;
// Speed up the effect for CD Loom since it uses it so often. I don't
// think the original had any delay at all, so on modern hardware it
// wasn't even noticeable.
- if (_game.id == GID_LOOM && (_game.version == 4))
- blitsBeforeRefresh *= 2;
+ //if (_game.id == GID_LOOM && (_game.version == 4))
+ // blitsBeforeRefresh *= 2;
for (i = 0; i < w * h; i++) {
x = offsets[i] % vs->pitch;
@@ -4097,10 +4097,6 @@ void ScummEngine::dissolveEffect(int width, int height) {
}
}
- if (blits != 0) {
- waitForTimer(4);
- }
-
free(offsets);
}
Commit: 6b838fd53acfda2c4f50ce60b38debb27f5faf26
https://github.com/scummvm/scummvm/commit/6b838fd53acfda2c4f50ce60b38debb27f5faf26
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: GFX: Update comments and kPictureDelay
Changed paths:
engines/scumm/gfx.cpp
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index a7fd2aed399..a5fab091f7e 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -66,7 +66,13 @@ struct StripTable {
enum {
kNoDelay = 0,
- kPictureDelay = 5
+ // This should actually be 3 in all games using it;
+ // every one of those games seems to accumulate some
+ // kind of internal random delay while performing
+ // the screen effect (like sound interrupts running,
+ // forcing the SCUMM timer to a lower frequency).
+ // I have added an extra quarter frame to emulate that.
+ kPictureDelay = 4
};
#define NUM_SHAKE_POSITIONS 8
@@ -81,11 +87,9 @@ static const int8 shake_positions[NUM_SHAKE_POSITIONS] = {
* that the screen has 40 vertical strips (i.e. 320 pixel), and 25 horizontal
* strips (i.e. 200 pixel). There is a hack in transitionEffect that
* makes it work correctly in games which have a different screen height
- * (for example, 240 pixel), but nothing is done regarding the width, so this
- * code won't work correctly in COMI. Also, the number of iteration depends
- * on min(vertStrips, horizStrips}. So the 13 is derived from 25/2, rounded up.
- * And the 25 = min(25,40). Hence for Zak256 instead of 13 and 25, the values
- * 15 and 30 should be used, and for COMI probably 30 and 60.
+ * (for example, 240 pixel), but nothing is done regarding the width.
+ * The number of iterations is hardcoded from version 3 up to 7.
+ * Version 8 doesn't have any of these effects at all.
*/
struct TransitionEffect {
byte numOfIterations;
Commit: 6eef97375eebc6c31f204b66e24cba4d41678347
https://github.com/scummvm/scummvm/commit/6eef97375eebc6c31f204b66e24cba4d41678347
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: GFX: Add clarificatory comment to scrollEffect()
Changed paths:
engines/scumm/gfx.cpp
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index a5fab091f7e..ffc924500e2 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -4116,6 +4116,9 @@ void ScummEngine::scrollEffect(int dir) {
int x, y;
const int step = 8;
+
+ // Keep in mind: this effect is only present in v5 and v6, so VAR_FADE_DELAY is
+ // never uninitialized. The following check is here for good measure only.
const int delay = (VAR_FADE_DELAY != 0xFF) ? VAR(VAR_FADE_DELAY) : kPictureDelay;
byte *src;
Commit: 9d236fa13b175bb5d0f2b261c7549d65e3c5b683
https://github.com/scummvm/scummvm/commit/9d236fa13b175bb5d0f2b261c7549d65e3c5b683
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: GFX: Finish implementation for dissolveEffect()
Changed paths:
engines/scumm/gfx.cpp
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index ffc924500e2..c1ff5d8f733 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -4002,11 +4002,12 @@ void ScummEngine::transitionEffect(int a) {
void ScummEngine::dissolveEffect(int width, int height) {
VirtScreen *vs = &_virtscr[kMainVirtScreen];
int *offsets;
- int blitsBeforeRefresh, blits;
+ int blitsBeforeRefresh, blits, blitsToFreeze;
int x, y;
int w, h;
int i;
-
+ bool canHalt = false;
+ bool is1x1Pattern = (width == height == 1);
// There's probably some less memory-hungry way of doing this. But
// since we're only dealing with relatively small images, it shouldn't
// be too bad.
@@ -4066,19 +4067,31 @@ void ScummEngine::dissolveEffect(int width, int height) {
free(offsets2);
}
- // Blit the image piece by piece to the screen. The idea here is that
- // the whole update should take about a quarter of a second, assuming
- // most of the time is spent in waitForTimer(). It looks good to me,
- // but might still need some tuning.
+ // The whole effect has a variable duration, depending on
+ // the host machine speed. We want to be accurate, but we
+ // also want to actually *see* the effect, given that in modern
+ // machines this code would run at lightspeed, so let's declare
+ // a blitsBeforeRefresh variable, which serves as a threshold
+ // value allowing us to pause rendering every N blits.
+ //
+ // Pattern 1x1:
+ // The original construct the image piece by piece but blits it
+ // every 8 iterations of a loop with duration h. We try to imitate
+ // this behavior by using blitsBeforeRefresh and by assigning it a value
+ // which is a factor of blitsToFreeze.
+ //
+ // Pattern NxM:
+ // The original construct the image piece by piece but blits it
+ // every time it finds an offset smaller than the height of the virtual
+ // screen. This is trivial to do in our code, so we just sleep for a
+ // quarter frame everytime the condition above is met.
+ //
+ // If we ever get a blitsToFreeze == 0, we will use 18 in its place
+ // since it's the most typical value got out of the calculations.
blits = 0;
- blitsBeforeRefresh = (w * h) / 8;
-
- // Speed up the effect for CD Loom since it uses it so often. I don't
- // think the original had any delay at all, so on modern hardware it
- // wasn't even noticeable.
- //if (_game.id == GID_LOOM && (_game.version == 4))
- // blitsBeforeRefresh *= 2;
+ blitsToFreeze = (h / 8); // The number of blits between which we delay rendering for pattern 1x1
+ blitsBeforeRefresh = (w * h) / (blitsToFreeze == 0 ? 18 : blitsToFreeze);
for (i = 0; i < w * h; i++) {
x = offsets[i] % vs->pitch;
@@ -4094,10 +4107,21 @@ void ScummEngine::dissolveEffect(int width, int height) {
else
_system->copyRectToScreen(vs->getPixels(x, y), vs->pitch, x, y + vs->topline, width, height);
+ // Test for 1x1 pattern...
+ canHalt |= is1x1Pattern && ++blits >= blitsBeforeRefresh;
- if (++blits >= blitsBeforeRefresh) {
+ // If that is true, then reset the blits var...
+ if (canHalt) {
blits = 0;
- waitForTimer(4);
+ }
+
+ // Test for NxM pattern...
+ canHalt |= !is1x1Pattern && (offsets[i] < vs->h);
+
+ // Halt rendering for a quarter frame...
+ if (canHalt) {
+ canHalt = false;
+ waitForTimer(1);
}
}
Commit: aa8c5285ebee4179b53404ff937987c6410dda11
https://github.com/scummvm/scummvm/commit/aa8c5285ebee4179b53404ff937987c6410dda11
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Fix comment
Changed paths:
engines/scumm/scumm.h
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 8fcba794ee9..391501c849e 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -281,7 +281,7 @@ typedef uint16 ResId;
class ResourceManager;
/**
- * DOS Programmable Interrupt Timer constants.
+ * DOS Programmable Interval Timer constants.
*
* The SCUMM engine (v1-v7, DOS) timer ticks are based on the jiffy unit (roughly 60Hz).
* Well, if we want to be pedantic about it, it operates on quarter jiffies (240Hz),
@@ -298,7 +298,7 @@ class ResourceManager;
* - Divisor: the base frequency in DOS is not used as-is, but it is instead
* divided by a customizable divisor which can range between
* 0 and (2^16-1), where 0 is a shortcut for 2^16. This operation
- * yields the custom frequency at which the custom assigned interrupt
+ * yields the custom frequency at which our custom interrupt
* gets called (hence "Programmable");
*
* - Orchestrator: starting from SCUMM v5, games started using iMUSE, and apparently
Commit: 38ac6fbadcb8f5c46c4173ea04dba5b4977b06f8
https://github.com/scummvm/scummvm/commit/38ac6fbadcb8f5c46c4173ea04dba5b4977b06f8
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: GFX: Fix bool comparison
Changed paths:
engines/scumm/gfx.cpp
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index c1ff5d8f733..101b3202f66 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -4007,7 +4007,7 @@ void ScummEngine::dissolveEffect(int width, int height) {
int w, h;
int i;
bool canHalt = false;
- bool is1x1Pattern = (width == height == 1);
+ bool is1x1Pattern = (width == 1 && height == 1);
// There's probably some less memory-hungry way of doing this. But
// since we're only dealing with relatively small images, it shouldn't
// be too bad.
Commit: 07eafca398854f0fe13feef7a7d9baf434e3683b
https://github.com/scummvm/scummvm/commit/07eafca398854f0fe13feef7a7d9baf434e3683b
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: INSANE: Set correct video framerate
Changed paths:
engines/scumm/insane/insane.cpp
diff --git a/engines/scumm/insane/insane.cpp b/engines/scumm/insane/insane.cpp
index 37997f0c968..f4f0444d03f 100644
--- a/engines/scumm/insane/insane.cpp
+++ b/engines/scumm/insane/insane.cpp
@@ -629,7 +629,7 @@ void Insane::startVideo(const char *filename, int num, int argC, int frameRate,
smush_setupSanFromStart(filename, 0, -1, -1, 0);
}
- _player->play(filename, _speed, offset, startFrame);
+ _player->play(filename, frameRate, offset, startFrame);
}
void Insane::smush_warpMouse(int x, int y, int buttons) {
Commit: 2d12acec5ab912559bc870844030c1dff9fdc763
https://github.com/scummvm/scummvm/commit/2d12acec5ab912559bc870844030c1dff9fdc763
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Add v7 quirk to IsMouthSyncOff()
Changed paths:
engines/scumm/sound.cpp
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 9ed8850db3a..edd388bcfcb 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -986,7 +986,12 @@ bool Sound::isMouthSyncOff(uint pos) {
break;
}
} while (pos + delay > j);
- return val;
+
+ if (_vm->_game.version < 7) {
+ return val;
+ } else {
+ return (j != 0xFFFF) ? val : false;
+ }
}
int Sound::isSoundRunning(int sound) const {
Commit: ebb3f2a8426737fed67df0a579cb9f640f8e1834
https://github.com/scummvm/scummvm/commit/ebb3f2a8426737fed67df0a579cb9f640f8e1834
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Implement Amiga timings
Changed paths:
engines/scumm/gfx.cpp
engines/scumm/scumm.cpp
engines/scumm/scumm.h
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 101b3202f66..78c1089565f 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -3935,6 +3935,10 @@ void ScummEngine::transitionEffect(int a) {
delay = VAR(VAR_FADE_DELAY);
}
+ if (_game.platform == Common::kPlatformAmiga) {
+ delay *= 4;
+ }
+
// V3+ games have the number of iterations hardcoded; we also
// have that number hardcoded for MM NES, so let's target that too:
if (_game.version >= 3 || _game.platform == Common::kPlatformNES) {
@@ -4118,10 +4122,14 @@ void ScummEngine::dissolveEffect(int width, int height) {
// Test for NxM pattern...
canHalt |= !is1x1Pattern && (offsets[i] < vs->h);
- // Halt rendering for a quarter frame...
+ // Halt rendering for a quarter frame (or a whole frame in case of Amiga)...
if (canHalt) {
canHalt = false;
- waitForTimer(1);
+ if (_game.platform == Common::kPlatformAmiga) {
+ waitForTimer(4);
+ } else {
+ waitForTimer(1);
+ }
}
}
@@ -4143,7 +4151,11 @@ void ScummEngine::scrollEffect(int dir) {
// Keep in mind: this effect is only present in v5 and v6, so VAR_FADE_DELAY is
// never uninitialized. The following check is here for good measure only.
- const int delay = (VAR_FADE_DELAY != 0xFF) ? VAR(VAR_FADE_DELAY) : kPictureDelay;
+ int delay = (VAR_FADE_DELAY != 0xFF) ? VAR(VAR_FADE_DELAY) : kPictureDelay;
+
+ if (_game.platform == Common::kPlatformAmiga) {
+ delay *= 4;
+ }
byte *src;
int m = _textSurfaceMultiplier;
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 39347740aef..46d15a2792c 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2264,6 +2264,8 @@ void ScummEngine::setTimerAndShakeFrequency() {
default:
_shakeTimerRate = _timerFrequency = 240.0;
}
+ } else if (_game.platform == Common::kPlatformAmiga) {
+ _shakeTimerRate = _timerFrequency = AMIGA_NTSC_VBLANK_RATE;
}
}
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 391501c849e..7c3400caa1b 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -332,6 +332,22 @@ class ResourceManager;
#define PIT_V7_SUBTIMER_INC 3977.0
#define PIT_V7_SUBTIMER_THRESH 4971.0
+/**
+ * Amiga timing constants.
+ *
+ * Amiga versions of SCUMM games update the game timer at every
+ * V-Blank interrupt, incrementing it by 4 each time (which means
+ * a full frame/jiffie). The shake timer is instead updated every
+ * other V-Blank interrupt, so 8 quarter frames (2 frames/jiffies)
+ * at a time.
+ *
+ * The base rate is 50Hz for PAL systems and 60Hz for NTSC systems.
+ * We're going to target the latter in here, converting it in a quarter
+ * frame frequency.
+ */
+
+#define AMIGA_NTSC_VBLANK_RATE 240.0
+
/**
* Base class for all SCUMM engines.
*/
Commit: ca527c8390022f54bf3863c4819d5ec1627f166d
https://github.com/scummvm/scummvm/commit/ca527c8390022f54bf3863c4819d5ec1627f166d
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-05-21T22:44:01+03:00
Commit Message:
SCUMM: Implement a better approximation of some Amiga quirks
Changed paths:
engines/scumm/gfx.cpp
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 78c1089565f..fce188bc18d 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -3935,8 +3935,17 @@ void ScummEngine::transitionEffect(int a) {
delay = VAR(VAR_FADE_DELAY);
}
+ // Amiga handles timing a whole frame at a time
+ // instead of using quarter frames; the following
+ // code gives my best approximation of that behavior
+ // and the resulting timing
if (_game.platform == Common::kPlatformAmiga) {
- delay *= 4;
+ int amigaRest = (delay % 4);
+ delay = (delay / 4);
+ if (amigaRest > 0) {
+ delay += 1;
+ }
+ delay *= 10;
}
// V3+ games have the number of iterations hardcoded; we also
@@ -4153,8 +4162,17 @@ void ScummEngine::scrollEffect(int dir) {
// never uninitialized. The following check is here for good measure only.
int delay = (VAR_FADE_DELAY != 0xFF) ? VAR(VAR_FADE_DELAY) : kPictureDelay;
+ // Amiga handles timing a whole frame at a time
+ // instead of using quarter frames; the following
+ // code gives my best approximation of that behavior
+ // and the resulting timing
if (_game.platform == Common::kPlatformAmiga) {
- delay *= 4;
+ int amigaRest = (delay % 4);
+ delay = (delay / 4);
+ if (amigaRest > 0) {
+ delay += 1;
+ }
+ delay *= 10;
}
byte *src;
More information about the Scummvm-git-logs
mailing list