aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS8
-rw-r--r--NEWS3
-rw-r--r--audio/softsynth/mt32/Analog.cpp348
-rw-r--r--audio/softsynth/mt32/Analog.h57
-rw-r--r--audio/softsynth/mt32/BReverbModel.cpp10
-rw-r--r--audio/softsynth/mt32/BReverbModel.h2
-rw-r--r--audio/softsynth/mt32/LA32FloatWaveGenerator.cpp2
-rw-r--r--audio/softsynth/mt32/LA32Ramp.cpp2
-rw-r--r--audio/softsynth/mt32/LA32WaveGenerator.cpp10
-rw-r--r--audio/softsynth/mt32/MemoryRegion.h124
-rw-r--r--audio/softsynth/mt32/MidiEventQueue.h67
-rw-r--r--audio/softsynth/mt32/Part.cpp1
-rw-r--r--audio/softsynth/mt32/Partial.cpp5
-rw-r--r--audio/softsynth/mt32/PartialManager.cpp1
-rw-r--r--audio/softsynth/mt32/Poly.cpp1
-rw-r--r--audio/softsynth/mt32/Poly.h1
-rw-r--r--audio/softsynth/mt32/ROMInfo.cpp15
-rw-r--r--audio/softsynth/mt32/ROMInfo.h4
-rw-r--r--audio/softsynth/mt32/Structures.h47
-rw-r--r--audio/softsynth/mt32/Synth.cpp248
-rw-r--r--audio/softsynth/mt32/Synth.h347
-rw-r--r--audio/softsynth/mt32/TVA.cpp1
-rw-r--r--audio/softsynth/mt32/TVF.cpp1
-rw-r--r--audio/softsynth/mt32/TVP.cpp1
-rw-r--r--audio/softsynth/mt32/Tables.cpp5
-rw-r--r--audio/softsynth/mt32/Tables.h15
-rw-r--r--audio/softsynth/mt32/Types.h40
-rw-r--r--audio/softsynth/mt32/internals.h83
-rw-r--r--audio/softsynth/mt32/module.mk1
-rw-r--r--audio/softsynth/mt32/mt32emu.h67
-rw-r--r--audio/timestamp.cpp6
-rwxr-xr-xdevtools/credits.pl8
-rw-r--r--engines/access/access.cpp17
-rw-r--r--engines/access/access.h1
-rw-r--r--engines/access/amazon/amazon_game.cpp22
-rw-r--r--engines/access/amazon/amazon_logic.cpp119
-rw-r--r--engines/access/amazon/amazon_logic.h2
-rw-r--r--engines/access/amazon/amazon_scripts.cpp32
-rw-r--r--engines/access/animation.cpp4
-rw-r--r--engines/access/animation.h1
-rw-r--r--engines/access/asurface.cpp20
-rw-r--r--engines/access/asurface.h10
-rw-r--r--engines/access/bubble_box.cpp7
-rw-r--r--engines/access/bubble_box.h4
-rw-r--r--engines/access/char.cpp4
-rw-r--r--engines/access/char.h3
-rw-r--r--engines/access/decompress.cpp5
-rw-r--r--engines/access/events.cpp2
-rw-r--r--engines/access/font.cpp2
-rw-r--r--engines/access/inventory.cpp1
-rw-r--r--engines/access/martian/martian_game.cpp10
-rw-r--r--engines/access/player.cpp7
-rw-r--r--engines/access/player.h1
-rw-r--r--engines/access/room.cpp6
-rw-r--r--engines/access/room.h1
-rw-r--r--engines/access/screen.cpp13
-rw-r--r--engines/access/screen.h6
-rw-r--r--engines/access/scripts.cpp6
-rw-r--r--engines/access/sound.cpp66
-rw-r--r--engines/access/sound.h10
-rw-r--r--engines/access/video.cpp13
-rw-r--r--engines/agi/detection.cpp6
-rw-r--r--engines/agi/loader_v2.cpp8
-rw-r--r--engines/agi/loader_v3.cpp5
-rw-r--r--engines/cge2/detection.cpp10
-rw-r--r--engines/drascula/detection.cpp3
-rw-r--r--engines/fullpipe/inventory.cpp2
-rw-r--r--engines/fullpipe/mgm.cpp7
-rw-r--r--engines/fullpipe/scenes/scene04.cpp9
-rw-r--r--engines/fullpipe/scenes/scene16.cpp2
-rw-r--r--engines/fullpipe/statics.cpp11
-rw-r--r--engines/sci/detection_tables.h14
-rw-r--r--engines/sci/engine/state.cpp2
-rw-r--r--engines/sci/graphics/portrait.cpp60
-rw-r--r--engines/sci/graphics/screen.cpp2
-rw-r--r--engines/zvision/core/console.cpp59
-rw-r--r--engines/zvision/core/console.h1
-rw-r--r--engines/zvision/core/events.cpp126
-rw-r--r--engines/zvision/detection.cpp100
-rw-r--r--engines/zvision/file/save_manager.cpp (renamed from engines/zvision/core/save_manager.cpp)31
-rw-r--r--engines/zvision/file/save_manager.h (renamed from engines/zvision/core/save_manager.h)10
-rw-r--r--engines/zvision/file/search_manager.cpp16
-rw-r--r--engines/zvision/file/search_manager.h18
-rw-r--r--engines/zvision/graphics/cursors/cursor.cpp38
-rw-r--r--engines/zvision/graphics/cursors/cursor.h1
-rw-r--r--engines/zvision/graphics/cursors/cursor_manager.cpp4
-rw-r--r--engines/zvision/graphics/cursors/cursor_manager.h4
-rw-r--r--engines/zvision/graphics/effects/fog.cpp12
-rw-r--r--engines/zvision/graphics/effects/fog.h5
-rw-r--r--engines/zvision/graphics/effects/light.cpp6
-rw-r--r--engines/zvision/graphics/effects/light.h4
-rw-r--r--engines/zvision/graphics/effects/wave.cpp2
-rw-r--r--engines/zvision/graphics/effects/wave.h4
-rw-r--r--engines/zvision/graphics/graphics_effect.h (renamed from engines/zvision/graphics/effect.h)14
-rw-r--r--engines/zvision/graphics/render_manager.cpp523
-rw-r--r--engines/zvision/graphics/render_manager.h49
-rw-r--r--engines/zvision/graphics/render_table.cpp21
-rw-r--r--engines/zvision/module.mk22
-rw-r--r--engines/zvision/scripting/actions.cpp185
-rw-r--r--engines/zvision/scripting/actions.h28
-rw-r--r--engines/zvision/scripting/control.cpp1
-rw-r--r--engines/zvision/scripting/control.h5
-rw-r--r--engines/zvision/scripting/controls/fist_control.cpp53
-rw-r--r--engines/zvision/scripting/controls/fist_control.h6
-rw-r--r--engines/zvision/scripting/controls/hotmov_control.cpp53
-rw-r--r--engines/zvision/scripting/controls/hotmov_control.h5
-rw-r--r--engines/zvision/scripting/controls/input_control.cpp25
-rw-r--r--engines/zvision/scripting/controls/lever_control.cpp4
-rw-r--r--engines/zvision/scripting/controls/lever_control.h1
-rw-r--r--engines/zvision/scripting/controls/paint_control.cpp12
-rw-r--r--engines/zvision/scripting/controls/paint_control.h1
-rw-r--r--engines/zvision/scripting/controls/safe_control.cpp53
-rw-r--r--engines/zvision/scripting/controls/safe_control.h8
-rw-r--r--engines/zvision/scripting/controls/save_control.cpp9
-rw-r--r--engines/zvision/scripting/controls/titler_control.cpp6
-rw-r--r--engines/zvision/scripting/controls/titler_control.h1
-rw-r--r--engines/zvision/scripting/effects/animation_effect.cpp (renamed from engines/zvision/scripting/sidefx/animation_node.cpp)167
-rw-r--r--engines/zvision/scripting/effects/animation_effect.h (renamed from engines/zvision/scripting/sidefx/animation_node.h)15
-rw-r--r--engines/zvision/scripting/effects/distort_effect.cpp (renamed from engines/zvision/scripting/sidefx/distort_node.cpp)5
-rw-r--r--engines/zvision/scripting/effects/distort_effect.h (renamed from engines/zvision/scripting/sidefx/distort_node.h)4
-rw-r--r--engines/zvision/scripting/effects/music_effect.cpp (renamed from engines/zvision/scripting/sidefx/music_node.cpp)20
-rw-r--r--engines/zvision/scripting/effects/music_effect.h (renamed from engines/zvision/scripting/sidefx/music_node.h)11
-rw-r--r--engines/zvision/scripting/effects/region_effect.cpp (renamed from engines/zvision/scripting/sidefx/region_node.cpp)6
-rw-r--r--engines/zvision/scripting/effects/region_effect.h (renamed from engines/zvision/scripting/sidefx/region_node.h)10
-rw-r--r--engines/zvision/scripting/effects/syncsound_effect.cpp (renamed from engines/zvision/scripting/sidefx/syncsound_node.cpp)6
-rw-r--r--engines/zvision/scripting/effects/syncsound_effect.h (renamed from engines/zvision/scripting/sidefx/syncsound_node.h)6
-rw-r--r--engines/zvision/scripting/effects/timer_effect.cpp (renamed from engines/zvision/scripting/sidefx/timer_node.cpp)4
-rw-r--r--engines/zvision/scripting/effects/timer_effect.h (renamed from engines/zvision/scripting/sidefx/timer_node.h)4
-rw-r--r--engines/zvision/scripting/effects/ttytext_effect.cpp (renamed from engines/zvision/scripting/sidefx/ttytext_node.cpp)12
-rw-r--r--engines/zvision/scripting/effects/ttytext_effect.h (renamed from engines/zvision/scripting/sidefx/ttytext_node.h)6
-rw-r--r--engines/zvision/scripting/menu.cpp (renamed from engines/zvision/core/menu.cpp)294
-rw-r--r--engines/zvision/scripting/menu.h (renamed from engines/zvision/core/menu.h)18
-rw-r--r--engines/zvision/scripting/scr_file_handling.cpp19
-rw-r--r--engines/zvision/scripting/script_manager.cpp19
-rw-r--r--engines/zvision/scripting/script_manager.h20
-rw-r--r--engines/zvision/scripting/scripting_effect.h (renamed from engines/zvision/scripting/sidefx.h)48
-rw-r--r--engines/zvision/sound/zork_raw.cpp16
-rw-r--r--engines/zvision/sound/zork_raw.h14
-rw-r--r--engines/zvision/text/string_manager.cpp11
-rw-r--r--engines/zvision/text/string_manager.h2
-rw-r--r--engines/zvision/text/subtitles.cpp (renamed from engines/zvision/graphics/subtitles.cpp)2
-rw-r--r--engines/zvision/text/subtitles.h (renamed from engines/zvision/graphics/subtitles.h)0
-rw-r--r--engines/zvision/text/text.cpp155
-rw-r--r--engines/zvision/text/text.h36
-rw-r--r--engines/zvision/text/truetype_font.cpp (renamed from engines/zvision/graphics/truetype_font.cpp)149
-rw-r--r--engines/zvision/text/truetype_font.h (renamed from engines/zvision/graphics/truetype_font.h)0
-rw-r--r--engines/zvision/video/rlf_decoder.cpp56
-rw-r--r--engines/zvision/video/rlf_decoder.h8
-rw-r--r--engines/zvision/video/video.cpp16
-rw-r--r--engines/zvision/video/zork_avi_decoder.cpp10
-rw-r--r--engines/zvision/zvision.cpp393
-rw-r--r--engines/zvision/zvision.h57
-rw-r--r--gui/credits.h14
-rw-r--r--gui/debugger.cpp56
-rw-r--r--gui/saveload-dialog.cpp17
-rw-r--r--test/audio/timestamp.h13
-rw-r--r--video/theora_decoder.h1
-rw-r--r--video/video_decoder.cpp4
158 files changed, 3032 insertions, 2285 deletions
diff --git a/AUTHORS b/AUTHORS
index 9470217230..3e8c65e5e2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -261,6 +261,8 @@ ScummVM Team
ZVision:
Adrian Astley
+ Filippos Karapetis
+ Anton Yarcev
Backend Teams
-------------
@@ -524,6 +526,12 @@ Other contributions
Victor Gonzalez - Soltys Spanish translation
Alejandro Gomez de la Munoza - Soltys Spanish translation
+ CGE2:
+ Arnaud Boutonne - Sfinx English translation
+ Thierry Crozat - Sfinx English translation
+ Peter Bozso - Sfinx English translation editor
+ Ryan Clark - Sfinx English translation editor
+
Drascula:
Thierry Crozat - Improve French translation
diff --git a/NEWS b/NEWS
index 762af70962..470ddc01bd 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,9 @@ For a more comprehensive changelog of the latest experimental code, see:
New Games:
- Added support for Sfinx.
+ General:
+ - Updated Munt MT-32 emulation code to version 1.5.0.
+
Broken Sword 1:
- Fix speech endianness detection on big endian systems for the mac
version (bug #6720).
diff --git a/audio/softsynth/mt32/Analog.cpp b/audio/softsynth/mt32/Analog.cpp
new file mode 100644
index 0000000000..8ac28e401a
--- /dev/null
+++ b/audio/softsynth/mt32/Analog.cpp
@@ -0,0 +1,348 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
+ * Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+//#include <cstring>
+#include "Analog.h"
+
+namespace MT32Emu {
+
+#if MT32EMU_USE_FLOAT_SAMPLES
+
+/* FIR approximation of the overall impulse response of the cascade composed of the sample & hold circuit and the low pass filter
+ * of the MT-32 first generation.
+ * The coefficients below are found by windowing the inverse DFT of the 1024 pin frequency response converted to the minimum phase.
+ * The frequency response of the LPF is computed directly, the effect of the S&H is approximated by multiplying the LPF frequency
+ * response by the corresponding sinc. Although, the LPF has DC gain of 3.2, we ignore this in the emulation and use normalised model.
+ * The peak gain of the normalised cascade appears about 1.7 near 11.8 kHz. Relative error doesn't exceed 1% for the frequencies
+ * below 12.5 kHz. In the higher frequency range, the relative error is below 8%. Peak error value is at 16 kHz.
+ */
+static const float COARSE_LPF_TAPS_MT32[] = {
+ 1.272473681f, -0.220267785f, -0.158039905f, 0.179603785f, -0.111484097f, 0.054137498f, -0.023518029f, 0.010997169f, -0.006935698f
+};
+
+// Similar approximation for new MT-32 and CM-32L/LAPC-I LPF. As the voltage controlled amplifier was introduced, LPF has unity DC gain.
+// The peak gain value shifted towards higher frequencies and a bit higher about 1.83 near 13 kHz.
+static const float COARSE_LPF_TAPS_CM32L[] = {
+ 1.340615635f, -0.403331694f, 0.036005517f, 0.066156844f, -0.069672532f, 0.049563806f, -0.031113416f, 0.019169774f, -0.012421368f
+};
+
+#else
+
+static const unsigned int COARSE_LPF_FRACTION_BITS = 14;
+
+// Integer versions of the FIRs above multiplied by (1 << 14) and rounded.
+static const SampleEx COARSE_LPF_TAPS_MT32[] = {
+ 20848, -3609, -2589, 2943, -1827, 887, -385, 180, -114
+};
+
+static const SampleEx COARSE_LPF_TAPS_CM32L[] = {
+ 21965, -6608, 590, 1084, -1142, 812, -510, 314, -204
+};
+
+#endif
+
+/* Combined FIR that both approximates the impulse response of the analogue circuits of sample & hold and the low pass filter
+ * in the audible frequency range (below 20 kHz) and attenuates unwanted mirror spectra above 28 kHz as well. It is a polyphase
+ * filter intended for resampling the signal to 48 kHz yet for applying high frequency boost.
+ * As with the filter above, the analogue LPF frequency response is obtained for 1536 pin grid for range up to 96 kHz and multiplied
+ * by the corresponding sinc. The result is further squared, windowed and passed to generalised Parks-McClellan routine as a desired response.
+ * Finally, the minimum phase factor is found that's essentially the coefficients below.
+ * Relative error in the audible frequency range doesn't exceed 0.0006%, attenuation in the stopband is better than 100 dB.
+ * This level of performance makes it nearly bit-accurate for standard 16-bit sample resolution.
+ */
+
+// FIR version for MT-32 first generation.
+static const float ACCURATE_LPF_TAPS_MT32[] = {
+ 0.003429281f, 0.025929869f, 0.096587777f, 0.228884848f, 0.372413431f, 0.412386503f, 0.263980018f,
+ -0.014504962f, -0.237394528f, -0.257043496f, -0.103436603f, 0.063996095f, 0.124562333f, 0.083703206f,
+ 0.013921662f, -0.033475018f, -0.046239712f, -0.029310921f, 0.00126585f, 0.021060961f, 0.017925605f,
+ 0.003559874f, -0.005105248f, -0.005647917f, -0.004157918f, -0.002065664f, 0.00158747f, 0.003762585f,
+ 0.001867137f, -0.001090028f, -0.001433979f, -0.00022367f, 4.34308E-05f, -0.000247827f, 0.000157087f,
+ 0.000605823f, 0.000197317f, -0.000370511f, -0.000261202f, 9.96069E-05f, 9.85073E-05f, -5.28754E-05f,
+ -1.00912E-05f, 7.69943E-05f, 2.03162E-05f, -5.67967E-05f, -3.30637E-05f, 1.61958E-05f, 1.73041E-05f
+};
+
+// FIR version for new MT-32 and CM-32L/LAPC-I.
+static const float ACCURATE_LPF_TAPS_CM32L[] = {
+ 0.003917452f, 0.030693861f, 0.116424199f, 0.275101674f, 0.43217361f, 0.431247894f, 0.183255659f,
+ -0.174955671f, -0.354240244f, -0.212401714f, 0.072259178f, 0.204655344f, 0.108336211f, -0.039099027f,
+ -0.075138174f, -0.026261906f, 0.00582663f, 0.003052193f, 0.00613657f, 0.017017951f, 0.008732535f,
+ -0.011027427f, -0.012933664f, 0.001158097f, 0.006765958f, 0.00046778f, -0.002191106f, 0.001561017f,
+ 0.001842871f, -0.001996876f, -0.002315836f, 0.000980965f, 0.001817454f, -0.000243272f, -0.000972848f,
+ 0.000149941f, 0.000498886f, -0.000204436f, -0.000347415f, 0.000142386f, 0.000249137f, -4.32946E-05f,
+ -0.000131231f, 3.88575E-07f, 4.48813E-05f, -1.31906E-06f, -1.03499E-05f, 7.71971E-06f, 2.86721E-06f
+};
+
+// According to the CM-64 PCB schematic, there is a difference in the values of the LPF entrance resistors for the reverb and non-reverb channels.
+// This effectively results in non-unity LPF DC gain for the reverb channel of 0.68 while the LPF has unity DC gain for the LA32 output channels.
+// In emulation, the reverb output gain is multiplied by this factor to compensate for the LPF gain difference.
+static const float CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR = 0.68f;
+
+static const unsigned int OUTPUT_GAIN_FRACTION_BITS = 8;
+static const float OUTPUT_GAIN_MULTIPLIER = float(1 << OUTPUT_GAIN_FRACTION_BITS);
+
+static const unsigned int COARSE_LPF_DELAY_LINE_LENGTH = 8; // Must be a power of 2
+static const unsigned int ACCURATE_LPF_DELAY_LINE_LENGTH = 16; // Must be a power of 2
+static const unsigned int ACCURATE_LPF_NUMBER_OF_PHASES = 3; // Upsampling factor
+static const unsigned int ACCURATE_LPF_PHASE_INCREMENT_REGULAR = 2; // Downsampling factor
+static const unsigned int ACCURATE_LPF_PHASE_INCREMENT_OVERSAMPLED = 1; // No downsampling
+static const Bit32u ACCURATE_LPF_DELTAS_REGULAR[][ACCURATE_LPF_NUMBER_OF_PHASES] = { { 0, 0, 0 }, { 1, 1, 0 }, { 1, 2, 1 } };
+static const Bit32u ACCURATE_LPF_DELTAS_OVERSAMPLED[][ACCURATE_LPF_NUMBER_OF_PHASES] = { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 0, 1 } };
+
+class AbstractLowPassFilter {
+public:
+ static AbstractLowPassFilter &createLowPassFilter(AnalogOutputMode mode, bool oldMT32AnalogLPF);
+ static void muteRingBuffer(SampleEx *ringBuffer, unsigned int length);
+
+ virtual ~AbstractLowPassFilter() {}
+ virtual SampleEx process(SampleEx sample) = 0;
+ virtual bool hasNextSample() const;
+ virtual unsigned int getOutputSampleRate() const;
+ virtual unsigned int estimateInSampleCount(unsigned int outSamples) const;
+ virtual void addPositionIncrement(unsigned int) {}
+};
+
+class NullLowPassFilter : public AbstractLowPassFilter {
+public:
+ SampleEx process(SampleEx sample);
+};
+
+class CoarseLowPassFilter : public AbstractLowPassFilter {
+private:
+ const SampleEx * const LPF_TAPS;
+ SampleEx ringBuffer[COARSE_LPF_DELAY_LINE_LENGTH];
+ unsigned int ringBufferPosition;
+
+public:
+ CoarseLowPassFilter(bool oldMT32AnalogLPF);
+ SampleEx process(SampleEx sample);
+};
+
+class AccurateLowPassFilter : public AbstractLowPassFilter {
+private:
+ const float * const LPF_TAPS;
+ const Bit32u (* const deltas)[ACCURATE_LPF_NUMBER_OF_PHASES];
+ const unsigned int phaseIncrement;
+ const unsigned int outputSampleRate;
+
+ SampleEx ringBuffer[ACCURATE_LPF_DELAY_LINE_LENGTH];
+ unsigned int ringBufferPosition;
+ unsigned int phase;
+
+public:
+ AccurateLowPassFilter(bool oldMT32AnalogLPF, bool oversample);
+ SampleEx process(SampleEx sample);
+ bool hasNextSample() const;
+ unsigned int getOutputSampleRate() const;
+ unsigned int estimateInSampleCount(unsigned int outSamples) const;
+ void addPositionIncrement(unsigned int positionIncrement);
+};
+
+Analog::Analog(const AnalogOutputMode mode, const ControlROMFeatureSet *controlROMFeatures) :
+ leftChannelLPF(AbstractLowPassFilter::createLowPassFilter(mode, controlROMFeatures->isOldMT32AnalogLPF())),
+ rightChannelLPF(AbstractLowPassFilter::createLowPassFilter(mode, controlROMFeatures->isOldMT32AnalogLPF())),
+ synthGain(0),
+ reverbGain(0)
+{}
+
+Analog::~Analog() {
+ delete &leftChannelLPF;
+ delete &rightChannelLPF;
+}
+
+void Analog::process(Sample **outStream, const Sample *nonReverbLeft, const Sample *nonReverbRight, const Sample *reverbDryLeft, const Sample *reverbDryRight, const Sample *reverbWetLeft, const Sample *reverbWetRight, Bit32u outLength) {
+ if (outStream == NULL) {
+ leftChannelLPF.addPositionIncrement(outLength);
+ rightChannelLPF.addPositionIncrement(outLength);
+ return;
+ }
+
+ while (0 < (outLength--)) {
+ SampleEx outSampleL;
+ SampleEx outSampleR;
+
+ if (leftChannelLPF.hasNextSample()) {
+ outSampleL = leftChannelLPF.process(0);
+ outSampleR = rightChannelLPF.process(0);
+ } else {
+ SampleEx inSampleL = ((SampleEx)*(nonReverbLeft++) + (SampleEx)*(reverbDryLeft++)) * synthGain + (SampleEx)*(reverbWetLeft++) * reverbGain;
+ SampleEx inSampleR = ((SampleEx)*(nonReverbRight++) + (SampleEx)*(reverbDryRight++)) * synthGain + (SampleEx)*(reverbWetRight++) * reverbGain;
+
+#if !MT32EMU_USE_FLOAT_SAMPLES
+ inSampleL >>= OUTPUT_GAIN_FRACTION_BITS;
+ inSampleR >>= OUTPUT_GAIN_FRACTION_BITS;
+#endif
+
+ outSampleL = leftChannelLPF.process(inSampleL);
+ outSampleR = rightChannelLPF.process(inSampleR);
+ }
+
+ *((*outStream)++) = Synth::clipSampleEx(outSampleL);
+ *((*outStream)++) = Synth::clipSampleEx(outSampleR);
+ }
+}
+
+unsigned int Analog::getOutputSampleRate() const {
+ return leftChannelLPF.getOutputSampleRate();
+}
+
+Bit32u Analog::getDACStreamsLength(Bit32u outputLength) const {
+ return leftChannelLPF.estimateInSampleCount(outputLength);
+}
+
+void Analog::setSynthOutputGain(float useSynthGain) {
+#if MT32EMU_USE_FLOAT_SAMPLES
+ synthGain = useSynthGain;
+#else
+ if (OUTPUT_GAIN_MULTIPLIER < useSynthGain) useSynthGain = OUTPUT_GAIN_MULTIPLIER;
+ synthGain = SampleEx(useSynthGain * OUTPUT_GAIN_MULTIPLIER);
+#endif
+}
+
+void Analog::setReverbOutputGain(float useReverbGain, bool mt32ReverbCompatibilityMode) {
+ if (!mt32ReverbCompatibilityMode) useReverbGain *= CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR;
+#if MT32EMU_USE_FLOAT_SAMPLES
+ reverbGain = useReverbGain;
+#else
+ if (OUTPUT_GAIN_MULTIPLIER < useReverbGain) useReverbGain = OUTPUT_GAIN_MULTIPLIER;
+ reverbGain = SampleEx(useReverbGain * OUTPUT_GAIN_MULTIPLIER);
+#endif
+}
+
+AbstractLowPassFilter &AbstractLowPassFilter::createLowPassFilter(AnalogOutputMode mode, bool oldMT32AnalogLPF) {
+ switch (mode) {
+ case AnalogOutputMode_COARSE:
+ return *new CoarseLowPassFilter(oldMT32AnalogLPF);
+ case AnalogOutputMode_ACCURATE:
+ return *new AccurateLowPassFilter(oldMT32AnalogLPF, false);
+ case AnalogOutputMode_OVERSAMPLED:
+ return *new AccurateLowPassFilter(oldMT32AnalogLPF, true);
+ default:
+ return *new NullLowPassFilter;
+ }
+}
+
+void AbstractLowPassFilter::muteRingBuffer(SampleEx *ringBuffer, unsigned int length) {
+
+#if MT32EMU_USE_FLOAT_SAMPLES
+
+ SampleEx *p = ringBuffer;
+ while (length--) {
+ *(p++) = 0.0f;
+ }
+
+#else
+
+ memset(ringBuffer, 0, length * sizeof(SampleEx));
+
+#endif
+
+}
+
+bool AbstractLowPassFilter::hasNextSample() const {
+ return false;
+}
+
+unsigned int AbstractLowPassFilter::getOutputSampleRate() const {
+ return SAMPLE_RATE;
+}
+
+unsigned int AbstractLowPassFilter::estimateInSampleCount(unsigned int outSamples) const {
+ return outSamples;
+}
+
+SampleEx NullLowPassFilter::process(const SampleEx inSample) {
+ return inSample;
+}
+
+CoarseLowPassFilter::CoarseLowPassFilter(bool oldMT32AnalogLPF) :
+ LPF_TAPS(oldMT32AnalogLPF ? COARSE_LPF_TAPS_MT32 : COARSE_LPF_TAPS_CM32L),
+ ringBufferPosition(0)
+{
+ muteRingBuffer(ringBuffer, COARSE_LPF_DELAY_LINE_LENGTH);
+}
+
+SampleEx CoarseLowPassFilter::process(const SampleEx inSample) {
+ static const unsigned int DELAY_LINE_MASK = COARSE_LPF_DELAY_LINE_LENGTH - 1;
+
+ SampleEx sample = LPF_TAPS[COARSE_LPF_DELAY_LINE_LENGTH] * ringBuffer[ringBufferPosition];
+ ringBuffer[ringBufferPosition] = Synth::clipSampleEx(inSample);
+
+ for (unsigned int i = 0; i < COARSE_LPF_DELAY_LINE_LENGTH; i++) {
+ sample += LPF_TAPS[i] * ringBuffer[(i + ringBufferPosition) & DELAY_LINE_MASK];
+ }
+
+ ringBufferPosition = (ringBufferPosition - 1) & DELAY_LINE_MASK;
+
+#if !MT32EMU_USE_FLOAT_SAMPLES
+ sample >>= COARSE_LPF_FRACTION_BITS;
+#endif
+
+ return sample;
+}
+
+AccurateLowPassFilter::AccurateLowPassFilter(const bool oldMT32AnalogLPF, const bool oversample) :
+ LPF_TAPS(oldMT32AnalogLPF ? ACCURATE_LPF_TAPS_MT32 : ACCURATE_LPF_TAPS_CM32L),
+ deltas(oversample ? ACCURATE_LPF_DELTAS_OVERSAMPLED : ACCURATE_LPF_DELTAS_REGULAR),
+ phaseIncrement(oversample ? ACCURATE_LPF_PHASE_INCREMENT_OVERSAMPLED : ACCURATE_LPF_PHASE_INCREMENT_REGULAR),
+ outputSampleRate(SAMPLE_RATE * ACCURATE_LPF_NUMBER_OF_PHASES / phaseIncrement),
+ ringBufferPosition(0),
+ phase(0)
+{
+ muteRingBuffer(ringBuffer, ACCURATE_LPF_DELAY_LINE_LENGTH);
+}
+
+SampleEx AccurateLowPassFilter::process(const SampleEx inSample) {
+ static const unsigned int DELAY_LINE_MASK = ACCURATE_LPF_DELAY_LINE_LENGTH - 1;
+
+ float sample = (phase == 0) ? LPF_TAPS[ACCURATE_LPF_DELAY_LINE_LENGTH * ACCURATE_LPF_NUMBER_OF_PHASES] * ringBuffer[ringBufferPosition] : 0.0f;
+ if (!hasNextSample()) {
+ ringBuffer[ringBufferPosition] = inSample;
+ }
+
+ for (unsigned int tapIx = phase, delaySampleIx = 0; delaySampleIx < ACCURATE_LPF_DELAY_LINE_LENGTH; delaySampleIx++, tapIx += ACCURATE_LPF_NUMBER_OF_PHASES) {
+ sample += LPF_TAPS[tapIx] * ringBuffer[(delaySampleIx + ringBufferPosition) & DELAY_LINE_MASK];
+ }
+
+ phase += phaseIncrement;
+ if (ACCURATE_LPF_NUMBER_OF_PHASES <= phase) {
+ phase -= ACCURATE_LPF_NUMBER_OF_PHASES;
+ ringBufferPosition = (ringBufferPosition - 1) & DELAY_LINE_MASK;
+ }
+
+ return SampleEx(ACCURATE_LPF_NUMBER_OF_PHASES * sample);
+}
+
+bool AccurateLowPassFilter::hasNextSample() const {
+ return phaseIncrement <= phase;
+}
+
+unsigned int AccurateLowPassFilter::getOutputSampleRate() const {
+ return outputSampleRate;
+}
+
+unsigned int AccurateLowPassFilter::estimateInSampleCount(unsigned int outSamples) const {
+ Bit32u cycleCount = outSamples / ACCURATE_LPF_NUMBER_OF_PHASES;
+ Bit32u remainder = outSamples - cycleCount * ACCURATE_LPF_NUMBER_OF_PHASES;
+ return cycleCount * phaseIncrement + deltas[remainder][phase];
+}
+
+void AccurateLowPassFilter::addPositionIncrement(const unsigned int positionIncrement) {
+ phase = (phase + positionIncrement * phaseIncrement) % ACCURATE_LPF_NUMBER_OF_PHASES;
+}
+
+}
diff --git a/audio/softsynth/mt32/Analog.h b/audio/softsynth/mt32/Analog.h
new file mode 100644
index 0000000000..a48db72485
--- /dev/null
+++ b/audio/softsynth/mt32/Analog.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
+ * Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MT32EMU_ANALOG_H
+#define MT32EMU_ANALOG_H
+
+#include "mt32emu.h"
+
+namespace MT32Emu {
+
+class AbstractLowPassFilter;
+
+/* Analog class is dedicated to perform fair emulation of analogue circuitry of hardware units that is responsible
+ * for processing output signal after the DAC. It appears that the analogue circuit labeled "LPF" on the schematic
+ * also applies audible changes to the signal spectra. There is a significant boost of higher frequencies observed
+ * aside from quite poor attenuation of the mirror spectra above 16 kHz which is due to a relatively low filter order.
+ *
+ * As the final mixing of multiplexed output signal is performed after the DAC, this function is migrated here from Synth.
+ * Saying precisely, mixing is performed within the LPF as the entrance resistors are actually components of a LPF
+ * designed using the multiple feedback topology. Nevertheless, the schematic separates them.
+ */
+class Analog {
+public:
+ Analog(AnalogOutputMode mode, const ControlROMFeatureSet *controlROMFeatures);
+ ~Analog();
+ void process(Sample **outStream, const Sample *nonReverbLeft, const Sample *nonReverbRight, const Sample *reverbDryLeft, const Sample *reverbDryRight, const Sample *reverbWetLeft, const Sample *reverbWetRight, const Bit32u outLength);
+ unsigned int getOutputSampleRate() const;
+ Bit32u getDACStreamsLength(Bit32u outputLength) const;
+ void setSynthOutputGain(float synthGain);
+ void setReverbOutputGain(float reverbGain, bool mt32ReverbCompatibilityMode);
+
+private:
+ AbstractLowPassFilter &leftChannelLPF;
+ AbstractLowPassFilter &rightChannelLPF;
+ SampleEx synthGain;
+ SampleEx reverbGain;
+
+ Analog(Analog &);
+};
+
+}
+
+#endif
diff --git a/audio/softsynth/mt32/BReverbModel.cpp b/audio/softsynth/mt32/BReverbModel.cpp
index 37b3e9670d..5e02db8f99 100644
--- a/audio/softsynth/mt32/BReverbModel.cpp
+++ b/audio/softsynth/mt32/BReverbModel.cpp
@@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-//#include <memory.h>
+//#include <cstring>
#include "mt32emu.h"
#include "BReverbModel.h"
@@ -501,9 +501,9 @@ void BReverbModel::process(const Sample *inLeft, const Sample *inRight, Sample *
* Analysing of the algorithm suggests that the overflow is most probable when the combs output is added below.
* So, despite this isn't actually accurate, we only add the check here for performance reasons.
*/
- Sample outSample = Synth::clipBit16s(Synth::clipBit16s(Synth::clipBit16s(Synth::clipBit16s((Bit32s)outL1 + Bit32s(outL1 >> 1)) + (Bit32s)outL2) + Bit32s(outL2 >> 1)) + (Bit32s)outL3);
+ Sample outSample = Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx((SampleEx)outL1 + SampleEx(outL1 >> 1)) + (SampleEx)outL2) + SampleEx(outL2 >> 1)) + (SampleEx)outL3);
#else
- Sample outSample = Synth::clipBit16s((Bit32s)outL1 + Bit32s(outL1 >> 1) + (Bit32s)outL2 + Bit32s(outL2 >> 1) + (Bit32s)outL3);
+ Sample outSample = Synth::clipSampleEx((SampleEx)outL1 + SampleEx(outL1 >> 1) + (SampleEx)outL2 + SampleEx(outL2 >> 1) + (SampleEx)outL3);
#endif
*(outLeft++) = weirdMul(outSample, wetLevel, 0xFF);
}
@@ -515,9 +515,9 @@ void BReverbModel::process(const Sample *inLeft, const Sample *inRight, Sample *
Sample outSample = 1.5f * (outR1 + outR2) + outR3;
#elif MT32EMU_BOSS_REVERB_PRECISE_MODE
// See the note above for the left channel output.
- Sample outSample = Synth::clipBit16s(Synth::clipBit16s(Synth::clipBit16s(Synth::clipBit16s((Bit32s)outR1 + Bit32s(outR1 >> 1)) + (Bit32s)outR2) + Bit32s(outR2 >> 1)) + (Bit32s)outR3);
+ Sample outSample = Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx((SampleEx)outR1 + SampleEx(outR1 >> 1)) + (SampleEx)outR2) + SampleEx(outR2 >> 1)) + (SampleEx)outR3);
#else
- Sample outSample = Synth::clipBit16s((Bit32s)outR1 + Bit32s(outR1 >> 1) + (Bit32s)outR2 + Bit32s(outR2 >> 1) + (Bit32s)outR3);
+ Sample outSample = Synth::clipSampleEx((SampleEx)outR1 + SampleEx(outR1 >> 1) + (SampleEx)outR2 + SampleEx(outR2 >> 1) + (SampleEx)outR3);
#endif
*(outRight++) = weirdMul(outSample, wetLevel, 0xFF);
}
diff --git a/audio/softsynth/mt32/BReverbModel.h b/audio/softsynth/mt32/BReverbModel.h
index 9b840900c3..764daf1a9e 100644
--- a/audio/softsynth/mt32/BReverbModel.h
+++ b/audio/softsynth/mt32/BReverbModel.h
@@ -95,7 +95,6 @@ class BReverbModel {
const bool tapDelayMode;
Bit32u dryAmp;
Bit32u wetLevel;
- void mute();
static const BReverbSettings &getCM32L_LAPCSettings(const ReverbMode mode);
static const BReverbSettings &getMT32Settings(const ReverbMode mode);
@@ -107,6 +106,7 @@ public:
void open();
// May be called multiple times without an open() in between.
void close();
+ void mute();
void setParameters(Bit8u time, Bit8u level);
void process(const Sample *inLeft, const Sample *inRight, Sample *outLeft, Sample *outRight, unsigned long numSamples);
bool isActive() const;
diff --git a/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp b/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
index 9265d80c88..42d820ebad 100644
--- a/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
+++ b/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
@@ -18,7 +18,7 @@
//#include <cmath>
#include "mt32emu.h"
#include "mmath.h"
-#include "LA32FloatWaveGenerator.h"
+#include "internals.h"
namespace MT32Emu {
diff --git a/audio/softsynth/mt32/LA32Ramp.cpp b/audio/softsynth/mt32/LA32Ramp.cpp
index 454612c842..2b31a330d2 100644
--- a/audio/softsynth/mt32/LA32Ramp.cpp
+++ b/audio/softsynth/mt32/LA32Ramp.cpp
@@ -50,8 +50,8 @@ We haven't fully explored:
//#include <cmath>
#include "mt32emu.h"
-#include "LA32Ramp.h"
#include "mmath.h"
+#include "internals.h"
namespace MT32Emu {
diff --git a/audio/softsynth/mt32/LA32WaveGenerator.cpp b/audio/softsynth/mt32/LA32WaveGenerator.cpp
index 7ac7cc6aaa..765f75fa61 100644
--- a/audio/softsynth/mt32/LA32WaveGenerator.cpp
+++ b/audio/softsynth/mt32/LA32WaveGenerator.cpp
@@ -15,15 +15,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-//#include <cmath>
-#include "mt32emu.h"
-#include "mmath.h"
-#include "LA32WaveGenerator.h"
-
#if MT32EMU_USE_FLOAT_SAMPLES
#include "LA32FloatWaveGenerator.cpp"
#else
+//#include <cmath>
+#include "mt32emu.h"
+#include "mmath.h"
+#include "internals.h"
+
namespace MT32Emu {
static const Bit32u SINE_SEGMENT_RELATIVE_LENGTH = 1 << 18;
diff --git a/audio/softsynth/mt32/MemoryRegion.h b/audio/softsynth/mt32/MemoryRegion.h
new file mode 100644
index 0000000000..c0cb041e11
--- /dev/null
+++ b/audio/softsynth/mt32/MemoryRegion.h
@@ -0,0 +1,124 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
+ * Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MT32EMU_MEMORY_REGION_H
+#define MT32EMU_MEMORY_REGION_H
+
+namespace MT32Emu {
+
+enum MemoryRegionType {
+ MR_PatchTemp, MR_RhythmTemp, MR_TimbreTemp, MR_Patches, MR_Timbres, MR_System, MR_Display, MR_Reset
+};
+
+class MemoryRegion {
+private:
+ Synth *synth;
+ Bit8u *realMemory;
+ Bit8u *maxTable;
+public:
+ MemoryRegionType type;
+ Bit32u startAddr, entrySize, entries;
+
+ MemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable, MemoryRegionType useType, Bit32u useStartAddr, Bit32u useEntrySize, Bit32u useEntries) {
+ synth = useSynth;
+ realMemory = useRealMemory;
+ maxTable = useMaxTable;
+ type = useType;
+ startAddr = useStartAddr;
+ entrySize = useEntrySize;
+ entries = useEntries;
+ }
+ int lastTouched(Bit32u addr, Bit32u len) const {
+ return (offset(addr) + len - 1) / entrySize;
+ }
+ int firstTouchedOffset(Bit32u addr) const {
+ return offset(addr) % entrySize;
+ }
+ int firstTouched(Bit32u addr) const {
+ return offset(addr) / entrySize;
+ }
+ Bit32u regionEnd() const {
+ return startAddr + entrySize * entries;
+ }
+ bool contains(Bit32u addr) const {
+ return addr >= startAddr && addr < regionEnd();
+ }
+ int offset(Bit32u addr) const {
+ return addr - startAddr;
+ }
+ Bit32u getClampedLen(Bit32u addr, Bit32u len) const {
+ if (addr + len > regionEnd())
+ return regionEnd() - addr;
+ return len;
+ }
+ Bit32u next(Bit32u addr, Bit32u len) const {
+ if (addr + len > regionEnd()) {
+ return regionEnd() - addr;
+ }
+ return 0;
+ }
+ Bit8u getMaxValue(int off) const {
+ if (maxTable == NULL)
+ return 0xFF;
+ return maxTable[off % entrySize];
+ }
+ Bit8u *getRealMemory() const {
+ return realMemory;
+ }
+ bool isReadable() const {
+ return getRealMemory() != NULL;
+ }
+ void read(unsigned int entry, unsigned int off, Bit8u *dst, unsigned int len) const;
+ void write(unsigned int entry, unsigned int off, const Bit8u *src, unsigned int len, bool init = false) const;
+};
+
+class PatchTempMemoryRegion : public MemoryRegion {
+public:
+ PatchTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_PatchTemp, MT32EMU_MEMADDR(0x030000), sizeof(MemParams::PatchTemp), 9) {}
+};
+class RhythmTempMemoryRegion : public MemoryRegion {
+public:
+ RhythmTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_RhythmTemp, MT32EMU_MEMADDR(0x030110), sizeof(MemParams::RhythmTemp), 85) {}
+};
+class TimbreTempMemoryRegion : public MemoryRegion {
+public:
+ TimbreTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_TimbreTemp, MT32EMU_MEMADDR(0x040000), sizeof(TimbreParam), 8) {}
+};
+class PatchesMemoryRegion : public MemoryRegion {
+public:
+ PatchesMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_Patches, MT32EMU_MEMADDR(0x050000), sizeof(PatchParam), 128) {}
+};
+class TimbresMemoryRegion : public MemoryRegion {
+public:
+ TimbresMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_Timbres, MT32EMU_MEMADDR(0x080000), sizeof(MemParams::PaddedTimbre), 64 + 64 + 64 + 64) {}
+};
+class SystemMemoryRegion : public MemoryRegion {
+public:
+ SystemMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_System, MT32EMU_MEMADDR(0x100000), sizeof(MemParams::System), 1) {}
+};
+class DisplayMemoryRegion : public MemoryRegion {
+public:
+ DisplayMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Display, MT32EMU_MEMADDR(0x200000), MAX_SYSEX_SIZE - 1, 1) {}
+};
+class ResetMemoryRegion : public MemoryRegion {
+public:
+ ResetMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Reset, MT32EMU_MEMADDR(0x7F0000), 0x3FFF, 1) {}
+};
+
+}
+
+#endif
diff --git a/audio/softsynth/mt32/MidiEventQueue.h b/audio/softsynth/mt32/MidiEventQueue.h
new file mode 100644
index 0000000000..b1948c5f8e
--- /dev/null
+++ b/audio/softsynth/mt32/MidiEventQueue.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
+ * Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MT32EMU_MIDI_EVENT_QUEUE_H
+#define MT32EMU_MIDI_EVENT_QUEUE_H
+
+namespace MT32Emu {
+
+/**
+ * Used to safely store timestamped MIDI events in a local queue.
+ */
+struct MidiEvent {
+ Bit32u shortMessageData;
+ const Bit8u *sysexData;
+ Bit32u sysexLength;
+ Bit32u timestamp;
+
+ ~MidiEvent();
+ void setShortMessage(Bit32u shortMessageData, Bit32u timestamp);
+ void setSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp);
+};
+
+/**
+ * Simple queue implementation using a ring buffer to store incoming MIDI event before the synth actually processes it.
+ * It is intended to:
+ * - get rid of prerenderer while retaining graceful partial abortion
+ * - add fair emulation of the MIDI interface delays
+ * - extend the synth interface with the default implementation of a typical rendering loop.
+ * THREAD SAFETY:
+ * It is safe to use either in a single thread environment or when there are only two threads - one performs only reading
+ * and one performs only writing. More complicated usage requires external synchronisation.
+ */
+class MidiEventQueue {
+private:
+ MidiEvent * const ringBuffer;
+ const Bit32u ringBufferMask;
+ volatile Bit32u startPosition;
+ volatile Bit32u endPosition;
+
+public:
+ MidiEventQueue(Bit32u ringBufferSize = DEFAULT_MIDI_EVENT_QUEUE_SIZE); // Must be a power of 2
+ ~MidiEventQueue();
+ void reset();
+ bool pushShortMessage(Bit32u shortMessageData, Bit32u timestamp);
+ bool pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp);
+ const MidiEvent *peekMidiEvent();
+ void dropMidiEvent();
+ bool isFull() const;
+};
+
+}
+
+#endif
diff --git a/audio/softsynth/mt32/Part.cpp b/audio/softsynth/mt32/Part.cpp
index d92473b5db..cffc3ed744 100644
--- a/audio/softsynth/mt32/Part.cpp
+++ b/audio/softsynth/mt32/Part.cpp
@@ -19,6 +19,7 @@
//#include <cstring>
#include "mt32emu.h"
+#include "internals.h"
#include "PartialManager.h"
namespace MT32Emu {
diff --git a/audio/softsynth/mt32/Partial.cpp b/audio/softsynth/mt32/Partial.cpp
index 7dcc6e945a..7348087509 100644
--- a/audio/softsynth/mt32/Partial.cpp
+++ b/audio/softsynth/mt32/Partial.cpp
@@ -21,6 +21,7 @@
#include "mt32emu.h"
#include "mmath.h"
+#include "internals.h"
namespace MT32Emu {
@@ -312,8 +313,8 @@ bool Partial::produceOutput(Sample *leftBuf, Sample *rightBuf, unsigned long len
// Though, it is unknown whether this overflow is exploited somewhere.
Sample leftOut = Sample((sample * leftPanValue) >> 8);
Sample rightOut = Sample((sample * rightPanValue) >> 8);
- *leftBuf = Synth::clipBit16s((Bit32s)*leftBuf + (Bit32s)leftOut);
- *rightBuf = Synth::clipBit16s((Bit32s)*rightBuf + (Bit32s)rightOut);
+ *leftBuf = Synth::clipSampleEx((SampleEx)*leftBuf + (SampleEx)leftOut);
+ *rightBuf = Synth::clipSampleEx((SampleEx)*rightBuf + (SampleEx)rightOut);
leftBuf++;
rightBuf++;
#endif
diff --git a/audio/softsynth/mt32/PartialManager.cpp b/audio/softsynth/mt32/PartialManager.cpp
index fe73087581..8ca6e4e3d7 100644
--- a/audio/softsynth/mt32/PartialManager.cpp
+++ b/audio/softsynth/mt32/PartialManager.cpp
@@ -18,6 +18,7 @@
//#include <cstring>
#include "mt32emu.h"
+#include "internals.h"
#include "PartialManager.h"
namespace MT32Emu {
diff --git a/audio/softsynth/mt32/Poly.cpp b/audio/softsynth/mt32/Poly.cpp
index e07ceb4231..badcd8fb96 100644
--- a/audio/softsynth/mt32/Poly.cpp
+++ b/audio/softsynth/mt32/Poly.cpp
@@ -16,6 +16,7 @@
*/
#include "mt32emu.h"
+#include "internals.h"
namespace MT32Emu {
diff --git a/audio/softsynth/mt32/Poly.h b/audio/softsynth/mt32/Poly.h
index 9c6431ce36..e2614369bb 100644
--- a/audio/softsynth/mt32/Poly.h
+++ b/audio/softsynth/mt32/Poly.h
@@ -21,6 +21,7 @@
namespace MT32Emu {
class Part;
+class Partial;
enum PolyState {
POLY_Playing,
diff --git a/audio/softsynth/mt32/ROMInfo.cpp b/audio/softsynth/mt32/ROMInfo.cpp
index eb9622620f..7c0127078b 100644
--- a/audio/softsynth/mt32/ROMInfo.cpp
+++ b/audio/softsynth/mt32/ROMInfo.cpp
@@ -21,8 +21,8 @@
namespace MT32Emu {
static const ROMInfo *getKnownROMInfoFromList(unsigned int index) {
- static const ControlROMFeatureSet MT32_COMPATIBLE(true);
- static const ControlROMFeatureSet CM32L_COMPATIBLE(false);
+ static const ControlROMFeatureSet MT32_COMPATIBLE(true, true);
+ static const ControlROMFeatureSet CM32L_COMPATIBLE(false, false);
// Known ROMs
static const ROMInfo CTRL_MT32_V1_04 = {65536, "5a5cb5a77d7d55ee69657c2f870416daed52dea7", ROMInfo::Control, "ctrl_mt32_1_04", "MT-32 Control v1.04", ROMInfo::Full, NULL, &MT32_COMPATIBLE};
@@ -106,7 +106,6 @@ void ROMImage::freeROMImage(const ROMImage *romImage) {
delete romImage;
}
-
Common::File* ROMImage::getFile() const {
return file;
}
@@ -115,11 +114,17 @@ const ROMInfo* ROMImage::getROMInfo() const {
return romInfo;
}
-ControlROMFeatureSet::ControlROMFeatureSet(bool useDefaultReverbMT32Compatible) : defaultReverbMT32Compatible(useDefaultReverbMT32Compatible) {
-}
+ControlROMFeatureSet::ControlROMFeatureSet(bool useDefaultReverbMT32Compatible, bool useOldMT32AnalogLPF) :
+ defaultReverbMT32Compatible(useDefaultReverbMT32Compatible),
+ oldMT32AnalogLPF(useOldMT32AnalogLPF)
+{}
bool ControlROMFeatureSet::isDefaultReverbMT32Compatible() const {
return defaultReverbMT32Compatible;
}
+bool ControlROMFeatureSet::isOldMT32AnalogLPF() const {
+ return oldMT32AnalogLPF;
+}
+
}
diff --git a/audio/softsynth/mt32/ROMInfo.h b/audio/softsynth/mt32/ROMInfo.h
index cecbb6054f..4682620a15 100644
--- a/audio/softsynth/mt32/ROMInfo.h
+++ b/audio/softsynth/mt32/ROMInfo.h
@@ -77,10 +77,12 @@ public:
struct ControlROMFeatureSet {
private:
unsigned int defaultReverbMT32Compatible : 1;
+ unsigned int oldMT32AnalogLPF : 1;
public:
- ControlROMFeatureSet(bool defaultReverbMT32Compatible);
+ ControlROMFeatureSet(bool defaultReverbMT32Compatible, bool oldMT32AnalogLPF);
bool isDefaultReverbMT32Compatible() const;
+ bool isOldMT32AnalogLPF() const;
};
}
diff --git a/audio/softsynth/mt32/Structures.h b/audio/softsynth/mt32/Structures.h
index 35dcee90d6..4dada3a847 100644
--- a/audio/softsynth/mt32/Structures.h
+++ b/audio/softsynth/mt32/Structures.h
@@ -31,19 +31,6 @@ namespace MT32Emu {
#define MT32EMU_ALIGN_PACKED __attribute__((packed))
#endif
-typedef unsigned int Bit32u;
-typedef signed int Bit32s;
-typedef unsigned short int Bit16u;
-typedef signed short int Bit16s;
-typedef unsigned char Bit8u;
-typedef signed char Bit8s;
-
-#if MT32EMU_USE_FLOAT_SAMPLES
-typedef float Sample;
-#else
-typedef Bit16s Sample;
-#endif
-
// The following structures represent the MT-32's memory
// Since sysex allows this memory to be written to in blocks of bytes,
// we keep this packed so that we can copy data into the various
@@ -184,7 +171,37 @@ struct MemParams {
#pragma pack()
#endif
-struct ControlROMPCMStruct;
+struct ControlROMMap {
+ Bit16u idPos;
+ Bit16u idLen;
+ const char *idBytes;
+ Bit16u pcmTable; // 4 * pcmCount bytes
+ Bit16u pcmCount;
+ Bit16u timbreAMap; // 128 bytes
+ Bit16u timbreAOffset;
+ bool timbreACompressed;
+ Bit16u timbreBMap; // 128 bytes
+ Bit16u timbreBOffset;
+ bool timbreBCompressed;
+ Bit16u timbreRMap; // 2 * timbreRCount bytes
+ Bit16u timbreRCount;
+ Bit16u rhythmSettings; // 4 * rhythmSettingsCount bytes
+ Bit16u rhythmSettingsCount;
+ Bit16u reserveSettings; // 9 bytes
+ Bit16u panSettings; // 8 bytes
+ Bit16u programSettings; // 8 bytes
+ Bit16u rhythmMaxTable; // 4 bytes
+ Bit16u patchMaxTable; // 16 bytes
+ Bit16u systemMaxTable; // 23 bytes
+ Bit16u timbreMaxTable; // 72 bytes
+};
+
+struct ControlROMPCMStruct {
+ Bit8u pos;
+ Bit8u len;
+ Bit8u pitchLSB;
+ Bit8u pitchMSB;
+};
struct PCMWaveEntry {
Bit32u addr;
@@ -216,8 +233,6 @@ struct PatchCache {
const TimbreParam::PartialParam *partialParam;
};
-class Partial; // Forward reference for class defined in partial.h
-
}
#endif
diff --git a/audio/softsynth/mt32/Synth.cpp b/audio/softsynth/mt32/Synth.cpp
index 3bff429875..6df7eb9e31 100644
--- a/audio/softsynth/mt32/Synth.cpp
+++ b/audio/softsynth/mt32/Synth.cpp
@@ -22,12 +22,19 @@
#include "mt32emu.h"
#include "mmath.h"
-#include "PartialManager.h"
+#include "internals.h"
+
+#include "Analog.h"
#include "BReverbModel.h"
-#include "common/debug.h"
+#include "MemoryRegion.h"
+#include "MidiEventQueue.h"
+#include "PartialManager.h"
namespace MT32Emu {
+// MIDI interface data transfer rate in samples. Used to simulate the transfer delay.
+static const double MIDI_DATA_TRANSFER_RATE = (double)SAMPLE_RATE / 31250.0 * 8.0;
+
static const ControlROMMap ControlROMMaps[7] = {
// ID IDc IDbytes PCMmap PCMc tmbrA tmbrAO, tmbrAC tmbrB tmbrBO, tmbrBC tmbrR trC rhythm rhyC rsrv panpot prog rhyMax patMax sysMax timMax
{0x4014, 22, "\000 ver1.04 14 July 87 ", 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73A6, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A},
@@ -46,18 +53,15 @@ static inline void advanceStreamPosition(Sample *&stream, Bit32u posDelta) {
}
}
-Bit8u Synth::calcSysexChecksum(const Bit8u *data, Bit32u len, Bit8u checksum) {
+Bit8u Synth::calcSysexChecksum(const Bit8u *data, const Bit32u len, const Bit8u initChecksum) {
+ unsigned int checksum = -initChecksum;
for (unsigned int i = 0; i < len; i++) {
- checksum = checksum + data[i];
+ checksum -= data[i];
}
- checksum = checksum & 0x7f;
- if (checksum) {
- checksum = 0x80 - checksum;
- }
- return checksum;
+ return Bit8u(checksum & 0x7f);
}
-Synth::Synth(ReportHandler *useReportHandler) {
+Synth::Synth(ReportHandler *useReportHandler) : mt32ram(*new MemParams()), mt32default(*new MemParams()) {
isOpen = false;
reverbOverridden = false;
partialCount = DEFAULT_MAX_PARTIALS;
@@ -75,6 +79,7 @@ Synth::Synth(ReportHandler *useReportHandler) {
reverbModels[i] = NULL;
}
reverbModel = NULL;
+ analog = NULL;
setDACInputMode(DACInputMode_NICE);
setMIDIDelayMode(MIDIDelayMode_DELAY_SHORT_MESSAGES_ONLY);
setOutputGain(1.0f);
@@ -92,6 +97,8 @@ Synth::~Synth() {
if (isDefaultReportHandler) {
delete reportHandler;
}
+ delete &mt32ram;
+ delete &mt32default;
}
void ReportHandler::showLCDMessage(const char *data) {
@@ -126,7 +133,7 @@ void Synth::printDebug(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
#if MT32EMU_DEBUG_SAMPLESTAMPS > 0
- reportHandler->printDebug("[%u] ", renderedSampleCount);
+ reportHandler->printDebug("[%u] ", (char *)&renderedSampleCount);
#endif
reportHandler->printDebug(fmt, ap);
va_end(ap);
@@ -211,10 +218,7 @@ MIDIDelayMode Synth::getMIDIDelayMode() const {
void Synth::setOutputGain(float newOutputGain) {
if (newOutputGain < 0.0f) newOutputGain = -newOutputGain;
outputGain = newOutputGain;
-#if !MT32EMU_USE_FLOAT_SAMPLES
- if (256.0f < newOutputGain) newOutputGain = 256.0f;
- effectiveOutputGain = int(newOutputGain * 256.0f);
-#endif
+ if (analog != NULL) analog->setSynthOutputGain(newOutputGain);
}
float Synth::getOutputGain() const {
@@ -224,13 +228,7 @@ float Synth::getOutputGain() const {
void Synth::setReverbOutputGain(float newReverbOutputGain) {
if (newReverbOutputGain < 0.0f) newReverbOutputGain = -newReverbOutputGain;
reverbOutputGain = newReverbOutputGain;
- if (!isMT32ReverbCompatibilityMode()) newReverbOutputGain *= CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR;
-#if MT32EMU_USE_FLOAT_SAMPLES
- effectiveReverbOutputGain = newReverbOutputGain;
-#else
- if (256.0f < newReverbOutputGain) newReverbOutputGain = 256.0f;
- effectiveReverbOutputGain = int(newReverbOutputGain * 256.0f);
-#endif
+ if (analog != NULL) analog->setReverbOutputGain(newReverbOutputGain, isMT32ReverbCompatibilityMode());
}
float Synth::getReverbOutputGain() const {
@@ -393,7 +391,11 @@ bool Synth::initTimbres(Bit16u mapAddress, Bit16u offset, int count, int startTi
return true;
}
-bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, unsigned int usePartialCount) {
+bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, AnalogOutputMode analogOutputMode) {
+ return open(controlROMImage, pcmROMImage, DEFAULT_MAX_PARTIALS, analogOutputMode);
+}
+
+bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, unsigned int usePartialCount, AnalogOutputMode analogOutputMode) {
if (isOpen) {
return false;
}
@@ -548,6 +550,10 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, u
midiQueue = new MidiEventQueue();
+ analog = new Analog(analogOutputMode, controlROMFeatures);
+ setOutputGain(outputGain);
+ setReverbOutputGain(reverbOutputGain);
+
isOpen = true;
isEnabled = false;
@@ -565,6 +571,9 @@ void Synth::close(bool forced) {
delete midiQueue;
midiQueue = NULL;
+ delete analog;
+ analog = NULL;
+
delete partialManager;
partialManager = NULL;
@@ -603,16 +612,37 @@ void Synth::flushMIDIQueue() {
}
}
-void Synth::setMIDIEventQueueSize(Bit32u useSize) {
- if (midiQueue != NULL) {
- flushMIDIQueue();
- delete midiQueue;
- midiQueue = new MidiEventQueue(useSize);
+Bit32u Synth::setMIDIEventQueueSize(Bit32u useSize) {
+ static const Bit32u MAX_QUEUE_SIZE = (1 << 24); // This results in about 256 Mb - much greater than any reasonable value
+
+ if (midiQueue == NULL) return 0;
+ flushMIDIQueue();
+
+ // Find a power of 2 that is >= useSize
+ Bit32u binarySize = 1;
+ if (useSize < MAX_QUEUE_SIZE) {
+ // Using simple linear search as this isn't time critical
+ while (binarySize < useSize) binarySize <<= 1;
+ } else {
+ binarySize = MAX_QUEUE_SIZE;
}
+ delete midiQueue;
+ midiQueue = new MidiEventQueue(binarySize);
+ return binarySize;
}
Bit32u Synth::getShortMessageLength(Bit32u msg) {
- if ((msg & 0xF0) == 0xF0) return 1;
+ if ((msg & 0xF0) == 0xF0) {
+ switch (msg & 0xFF) {
+ case 0xF1:
+ case 0xF3:
+ return 2;
+ case 0xF2:
+ return 3;
+ default:
+ return 1;
+ }
+ }
// NOTE: This calculation isn't quite correct
// as it doesn't consider the running status byte
return ((msg & 0xE0) == 0xC0) ? 2 : 3;
@@ -638,6 +668,7 @@ bool Synth::playMsg(Bit32u msg, Bit32u timestamp) {
if (midiDelayMode != MIDIDelayMode_IMMEDIATE) {
timestamp = addMIDIInterfaceDelay(getShortMessageLength(msg), timestamp);
}
+ if (!isEnabled) isEnabled = true;
return midiQueue->pushShortMessage(msg, timestamp);
}
@@ -650,16 +681,19 @@ bool Synth::playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp) {
if (midiDelayMode == MIDIDelayMode_DELAY_ALL) {
timestamp = addMIDIInterfaceDelay(len, timestamp);
}
+ if (!isEnabled) isEnabled = true;
return midiQueue->pushSysex(sysex, len, timestamp);
}
void Synth::playMsgNow(Bit32u msg) {
- // FIXME: Implement active sensing
+ // NOTE: Active sense IS implemented in real hardware. However, realtime processing is clearly out of the library scope.
+ // It is assumed that realtime consumers of the library respond to these MIDI events as appropriate.
+
unsigned char code = (unsigned char)((msg & 0x0000F0) >> 4);
unsigned char chan = (unsigned char)(msg & 0x00000F);
unsigned char note = (unsigned char)((msg & 0x007F00) >> 8);
unsigned char velocity = (unsigned char)((msg & 0x7F0000) >> 16);
- isEnabled = true;
+ if (!isEnabled) isEnabled = true;
//printDebug("Playing chan %d, code 0x%01x note: 0x%02x", chan, code, note);
@@ -831,7 +865,7 @@ void Synth::playSysexWithoutHeader(unsigned char device, unsigned char command,
printDebug("playSysexWithoutHeader: Message is too short (%d bytes)!", len);
return;
}
- unsigned char checksum = calcSysexChecksum(sysex, len - 1, 0);
+ Bit8u checksum = calcSysexChecksum(sysex, len - 1);
if (checksum != sysex[len - 1]) {
printDebug("playSysexWithoutHeader: Message checksum is incorrect (provided: %02x, expected: %02x)!", sysex[len - 1], checksum);
return;
@@ -1410,9 +1444,8 @@ void MidiEvent::setSysex(const Bit8u *useSysexData, Bit32u useSysexLength, Bit32
memcpy(dstSysexData, useSysexData, sysexLength);
}
-MidiEventQueue::MidiEventQueue(Bit32u useRingBufferSize) : ringBufferSize(useRingBufferSize) {
- ringBuffer = new MidiEvent[ringBufferSize];
- memset(ringBuffer, 0, ringBufferSize * sizeof(MidiEvent));
+MidiEventQueue::MidiEventQueue(Bit32u useRingBufferSize) : ringBuffer(new MidiEvent[useRingBufferSize]), ringBufferMask(useRingBufferSize - 1) {
+ memset(ringBuffer, 0, useRingBufferSize * sizeof(MidiEvent));
reset();
}
@@ -1426,7 +1459,7 @@ void MidiEventQueue::reset() {
}
bool MidiEventQueue::pushShortMessage(Bit32u shortMessageData, Bit32u timestamp) {
- unsigned int newEndPosition = (endPosition + 1) % ringBufferSize;
+ Bit32u newEndPosition = (endPosition + 1) & ringBufferMask;
// Is ring buffer full?
if (startPosition == newEndPosition) return false;
ringBuffer[endPosition].setShortMessage(shortMessageData, timestamp);
@@ -1435,7 +1468,7 @@ bool MidiEventQueue::pushShortMessage(Bit32u shortMessageData, Bit32u timestamp)
}
bool MidiEventQueue::pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp) {
- unsigned int newEndPosition = (endPosition + 1) % ringBufferSize;
+ Bit32u newEndPosition = (endPosition + 1) & ringBufferMask;
// Is ring buffer full?
if (startPosition == newEndPosition) return false;
ringBuffer[endPosition].setSysex(sysexData, sysexLength, timestamp);
@@ -1450,31 +1483,36 @@ const MidiEvent *MidiEventQueue::peekMidiEvent() {
void MidiEventQueue::dropMidiEvent() {
// Is ring buffer empty?
if (startPosition != endPosition) {
- startPosition = (startPosition + 1) % ringBufferSize;
+ startPosition = (startPosition + 1) & ringBufferMask;
}
}
+bool MidiEventQueue::isFull() const {
+ return startPosition == ((endPosition + 1) & ringBufferMask);
+}
+
+unsigned int Synth::getStereoOutputSampleRate() const {
+ return (analog == NULL) ? SAMPLE_RATE : analog->getOutputSampleRate();
+}
+
void Synth::render(Sample *stream, Bit32u len) {
- Sample tmpNonReverbLeft[MAX_SAMPLES_PER_RUN];
- Sample tmpNonReverbRight[MAX_SAMPLES_PER_RUN];
- Sample tmpReverbDryLeft[MAX_SAMPLES_PER_RUN];
- Sample tmpReverbDryRight[MAX_SAMPLES_PER_RUN];
- Sample tmpReverbWetLeft[MAX_SAMPLES_PER_RUN];
- Sample tmpReverbWetRight[MAX_SAMPLES_PER_RUN];
+ if (!isEnabled) {
+ renderedSampleCount += analog->getDACStreamsLength(len);
+ analog->process(NULL, NULL, NULL, NULL, NULL, NULL, NULL, len);
+ muteSampleBuffer(stream, len << 1);
+ return;
+ }
+
+ // As in AnalogOutputMode_ACCURATE mode output is upsampled, buffer size MAX_SAMPLES_PER_RUN is more than enough.
+ Sample tmpNonReverbLeft[MAX_SAMPLES_PER_RUN], tmpNonReverbRight[MAX_SAMPLES_PER_RUN];
+ Sample tmpReverbDryLeft[MAX_SAMPLES_PER_RUN], tmpReverbDryRight[MAX_SAMPLES_PER_RUN];
+ Sample tmpReverbWetLeft[MAX_SAMPLES_PER_RUN], tmpReverbWetRight[MAX_SAMPLES_PER_RUN];
while (len > 0) {
- Bit32u thisLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len;
- renderStreams(tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, thisLen);
- for (Bit32u i = 0; i < thisLen; i++) {
-#if MT32EMU_USE_FLOAT_SAMPLES
- *(stream++) = tmpNonReverbLeft[i] + tmpReverbDryLeft[i] + tmpReverbWetLeft[i];
- *(stream++) = tmpNonReverbRight[i] + tmpReverbDryRight[i] + tmpReverbWetRight[i];
-#else
- *(stream++) = clipBit16s((Bit32s)tmpNonReverbLeft[i] + (Bit32s)tmpReverbDryLeft[i] + (Bit32s)tmpReverbWetLeft[i]);
- *(stream++) = clipBit16s((Bit32s)tmpNonReverbRight[i] + (Bit32s)tmpReverbDryRight[i] + (Bit32s)tmpReverbWetRight[i]);
-#endif
- }
- len -= thisLen;
+ Bit32u thisPassLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len;
+ renderStreams(tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, analog->getDACStreamsLength(thisPassLen));
+ analog->process(&stream, tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, thisPassLen);
+ len -= thisPassLen;
}
}
@@ -1518,7 +1556,10 @@ void Synth::renderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample
// In GENERATION2 units, the output from LA32 goes to the Boss chip already bit-shifted.
// In NICE mode, it's also better to increase volume before the reverb processing to preserve accuracy.
void Synth::produceLA32Output(Sample *buffer, Bit32u len) {
-#if !MT32EMU_USE_FLOAT_SAMPLES
+#if MT32EMU_USE_FLOAT_SAMPLES
+ (void)buffer;
+ (void)len;
+#else
switch (dacInputMode) {
case DACInputMode_GENERATION2:
while (len--) {
@@ -1528,7 +1569,7 @@ void Synth::produceLA32Output(Sample *buffer, Bit32u len) {
break;
case DACInputMode_NICE:
while (len--) {
- *buffer = clipBit16s(Bit32s(*buffer) << 1);
+ *buffer = clipSampleEx(SampleEx(*buffer) << 1);
++buffer;
}
break;
@@ -1538,26 +1579,16 @@ void Synth::produceLA32Output(Sample *buffer, Bit32u len) {
#endif
}
-void Synth::convertSamplesToOutput(Sample *buffer, Bit32u len, bool reverb) {
- if (dacInputMode == DACInputMode_PURE) return;
-
+void Synth::convertSamplesToOutput(Sample *buffer, Bit32u len) {
#if MT32EMU_USE_FLOAT_SAMPLES
- float gain = reverb ? effectiveReverbOutputGain : outputGain;
- while (len--) {
- *(buffer++) *= gain;
- }
+ (void)buffer;
+ (void)len;
#else
- int gain = reverb ? effectiveReverbOutputGain : effectiveOutputGain;
if (dacInputMode == DACInputMode_GENERATION1) {
while (len--) {
- Bit32s target = Bit16s((*buffer & 0x8000) | ((*buffer << 1) & 0x7FFE));
- *(buffer++) = clipBit16s((target * gain) >> 8);
+ *buffer = Sample((*buffer & 0x8000) | ((*buffer << 1) & 0x7FFE));
+ ++buffer;
}
- return;
- }
- while (len--) {
- *buffer = clipBit16s((Bit32s(*buffer) * gain) >> 8);
- ++buffer;
}
#endif
}
@@ -1566,18 +1597,18 @@ void Synth::doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sampl
// Even if LA32 output isn't desired, we proceed anyway with temp buffers
Sample tmpBufNonReverbLeft[MAX_SAMPLES_PER_RUN], tmpBufNonReverbRight[MAX_SAMPLES_PER_RUN];
if (nonReverbLeft == NULL) nonReverbLeft = tmpBufNonReverbLeft;
- if (nonReverbLeft == NULL) nonReverbRight = tmpBufNonReverbRight;
+ if (nonReverbRight == NULL) nonReverbRight = tmpBufNonReverbRight;
Sample tmpBufReverbDryLeft[MAX_SAMPLES_PER_RUN], tmpBufReverbDryRight[MAX_SAMPLES_PER_RUN];
if (reverbDryLeft == NULL) reverbDryLeft = tmpBufReverbDryLeft;
if (reverbDryRight == NULL) reverbDryRight = tmpBufReverbDryRight;
- muteSampleBuffer(nonReverbLeft, len);
- muteSampleBuffer(nonReverbRight, len);
- muteSampleBuffer(reverbDryLeft, len);
- muteSampleBuffer(reverbDryRight, len);
-
if (isEnabled) {
+ muteSampleBuffer(nonReverbLeft, len);
+ muteSampleBuffer(nonReverbRight, len);
+ muteSampleBuffer(reverbDryLeft, len);
+ muteSampleBuffer(reverbDryRight, len);
+
for (unsigned int i = 0; i < getPartialCount(); i++) {
if (partialManager->shouldReverb(i)) {
partialManager->produceOutput(i, reverbDryLeft, reverbDryRight, len);
@@ -1591,8 +1622,8 @@ void Synth::doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sampl
if (isReverbEnabled()) {
reverbModel->process(reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, len);
- if (reverbWetLeft != NULL) convertSamplesToOutput(reverbWetLeft, len, true);
- if (reverbWetRight != NULL) convertSamplesToOutput(reverbWetRight, len, true);
+ if (reverbWetLeft != NULL) convertSamplesToOutput(reverbWetLeft, len);
+ if (reverbWetRight != NULL) convertSamplesToOutput(reverbWetRight, len);
} else {
muteSampleBuffer(reverbWetLeft, len);
muteSampleBuffer(reverbWetRight, len);
@@ -1601,15 +1632,20 @@ void Synth::doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sampl
// Don't bother with conversion if the output is going to be unused
if (nonReverbLeft != tmpBufNonReverbLeft) {
produceLA32Output(nonReverbLeft, len);
- convertSamplesToOutput(nonReverbLeft, len, false);
+ convertSamplesToOutput(nonReverbLeft, len);
}
if (nonReverbRight != tmpBufNonReverbRight) {
produceLA32Output(nonReverbRight, len);
- convertSamplesToOutput(nonReverbRight, len, false);
+ convertSamplesToOutput(nonReverbRight, len);
}
- if (reverbDryLeft != tmpBufReverbDryLeft) convertSamplesToOutput(reverbDryLeft, len, false);
- if (reverbDryRight != tmpBufReverbDryRight) convertSamplesToOutput(reverbDryRight, len, false);
+ if (reverbDryLeft != tmpBufReverbDryLeft) convertSamplesToOutput(reverbDryLeft, len);
+ if (reverbDryRight != tmpBufReverbDryRight) convertSamplesToOutput(reverbDryRight, len);
} else {
+ // Avoid muting buffers that wasn't requested
+ if (nonReverbLeft != tmpBufNonReverbLeft) muteSampleBuffer(nonReverbLeft, len);
+ if (nonReverbRight != tmpBufNonReverbRight) muteSampleBuffer(nonReverbRight, len);
+ if (reverbDryLeft != tmpBufReverbDryLeft) muteSampleBuffer(reverbDryLeft, len);
+ if (reverbDryRight != tmpBufReverbDryRight) muteSampleBuffer(reverbDryRight, len);
muteSampleBuffer(reverbWetLeft, len);
muteSampleBuffer(reverbWetRight, len);
}
@@ -1651,14 +1687,48 @@ bool Synth::isActive() const {
return false;
}
-const Partial *Synth::getPartial(unsigned int partialNum) const {
- return partialManager->getPartial(partialNum);
-}
-
unsigned int Synth::getPartialCount() const {
return partialCount;
}
+void Synth::getPartStates(bool *partStates) const {
+ for (int partNumber = 0; partNumber < 9; partNumber++) {
+ const Part *part = parts[partNumber];
+ partStates[partNumber] = part->getActiveNonReleasingPartialCount() > 0;
+ }
+}
+
+void Synth::getPartialStates(PartialState *partialStates) const {
+ static const PartialState partialPhaseToState[8] = {
+ PartialState_ATTACK, PartialState_ATTACK, PartialState_ATTACK, PartialState_ATTACK,
+ PartialState_SUSTAIN, PartialState_SUSTAIN, PartialState_RELEASE, PartialState_INACTIVE
+ };
+
+ for (unsigned int partialNum = 0; partialNum < getPartialCount(); partialNum++) {
+ const Partial *partial = partialManager->getPartial(partialNum);
+ partialStates[partialNum] = partial->isActive() ? partialPhaseToState[partial->getTVA()->getPhase()] : PartialState_INACTIVE;
+ }
+}
+
+unsigned int Synth::getPlayingNotes(unsigned int partNumber, Bit8u *keys, Bit8u *velocities) const {
+ unsigned int playingNotes = 0;
+ if (isOpen && (partNumber < 9)) {
+ const Part *part = parts[partNumber];
+ const Poly *poly = part->getFirstActivePoly();
+ while (poly != NULL) {
+ keys[playingNotes] = (Bit8u)poly->getKey();
+ velocities[playingNotes] = (Bit8u)poly->getVelocity();
+ playingNotes++;
+ poly = poly->getNext();
+ }
+ }
+ return playingNotes;
+}
+
+const char *Synth::getPatchName(unsigned int partNumber) const {
+ return (!isOpen || partNumber > 8) ? NULL : parts[partNumber]->getCurrentInstr();
+}
+
const Part *Synth::getPart(unsigned int partNum) const {
if (partNum > 8) {
return NULL;
diff --git a/audio/softsynth/mt32/Synth.h b/audio/softsynth/mt32/Synth.h
index 37fb7b280a..97d4644ee2 100644
--- a/audio/softsynth/mt32/Synth.h
+++ b/audio/softsynth/mt32/Synth.h
@@ -19,15 +19,31 @@
#define MT32EMU_SYNTH_H
//#include <cstdarg>
+//#include <cstring>
namespace MT32Emu {
-class TableInitialiser;
+class Analog;
+class BReverbModel;
+class MemoryRegion;
+class MidiEventQueue;
+class Part;
+class Poly;
class Partial;
class PartialManager;
-class Part;
-class ROMImage;
-class BReverbModel;
+
+class PatchTempMemoryRegion;
+class RhythmTempMemoryRegion;
+class TimbreTempMemoryRegion;
+class PatchesMemoryRegion;
+class TimbresMemoryRegion;
+class SystemMemoryRegion;
+class DisplayMemoryRegion;
+class ResetMemoryRegion;
+
+struct ControlROMMap;
+struct PCMWaveEntry;
+struct MemParams;
/**
* Methods for emulating the connection between the LA32 and the DAC, which involves
@@ -43,8 +59,7 @@ enum DACInputMode {
// Produces samples that exactly match the bits output from the emulated LA32.
// * Nicer overdrive characteristics than the DAC hacks (it simply clips samples within range)
// * Much less likely to overdrive than any other mode.
- // * Half the volume of any of the other modes, meaning its volume relative to the reverb
- // output when mixed together directly will sound wrong.
+ // * Half the volume of any of the other modes.
// * Output gain is ignored for both LA32 and reverb output.
// * Perfect for developers while debugging :)
DACInputMode_PURE,
@@ -60,6 +75,7 @@ enum DACInputMode {
DACInputMode_GENERATION2
};
+// Methods for emulating the effective delay of incoming MIDI messages introduced by a MIDI interface.
enum MIDIDelayMode {
// Process incoming MIDI events immediately.
MIDIDelayMode_IMMEDIATE,
@@ -72,6 +88,35 @@ enum MIDIDelayMode {
MIDIDelayMode_DELAY_ALL
};
+// Methods for emulating the effects of analogue circuits of real hardware units on the output signal.
+enum AnalogOutputMode {
+ // Only digital path is emulated. The output samples correspond to the digital signal at the DAC entrance.
+ AnalogOutputMode_DIGITAL_ONLY,
+ // Coarse emulation of LPF circuit. High frequencies are boosted, sample rate remains unchanged.
+ AnalogOutputMode_COARSE,
+ // Finer emulation of LPF circuit. Output signal is upsampled to 48 kHz to allow emulation of audible mirror spectra above 16 kHz,
+ // which is passed through the LPF circuit without significant attenuation.
+ AnalogOutputMode_ACCURATE,
+ // Same as AnalogOutputMode_ACCURATE mode but the output signal is 2x oversampled, i.e. the output sample rate is 96 kHz.
+ // This makes subsequent resampling easier. Besides, due to nonlinear passband of the LPF emulated, it takes fewer number of MACs
+ // compared to a regular LPF FIR implementations.
+ AnalogOutputMode_OVERSAMPLED
+};
+
+enum ReverbMode {
+ REVERB_MODE_ROOM,
+ REVERB_MODE_HALL,
+ REVERB_MODE_PLATE,
+ REVERB_MODE_TAP_DELAY
+};
+
+enum PartialState {
+ PartialState_INACTIVE,
+ PartialState_ATTACK,
+ PartialState_SUSTAIN,
+ PartialState_RELEASE
+};
+
const Bit8u SYSEX_MANUFACTURER_ROLAND = 0x41;
const Bit8u SYSEX_MDL_MT32 = 0x16;
@@ -87,148 +132,10 @@ const Bit8u SYSEX_CMD_EOD = 0x45; // End of data
const Bit8u SYSEX_CMD_ERR = 0x4E; // Communications error
const Bit8u SYSEX_CMD_RJC = 0x4F; // Rejection
-const int MAX_SYSEX_SIZE = 512;
+const int MAX_SYSEX_SIZE = 512; // FIXME: Does this correspond to a real MIDI buffer used in h/w devices?
const unsigned int CONTROL_ROM_SIZE = 64 * 1024;
-struct ControlROMPCMStruct {
- Bit8u pos;
- Bit8u len;
- Bit8u pitchLSB;
- Bit8u pitchMSB;
-};
-
-struct ControlROMMap {
- Bit16u idPos;
- Bit16u idLen;
- const char *idBytes;
- Bit16u pcmTable; // 4 * pcmCount bytes
- Bit16u pcmCount;
- Bit16u timbreAMap; // 128 bytes
- Bit16u timbreAOffset;
- bool timbreACompressed;
- Bit16u timbreBMap; // 128 bytes
- Bit16u timbreBOffset;
- bool timbreBCompressed;
- Bit16u timbreRMap; // 2 * timbreRCount bytes
- Bit16u timbreRCount;
- Bit16u rhythmSettings; // 4 * rhythmSettingsCount bytes
- Bit16u rhythmSettingsCount;
- Bit16u reserveSettings; // 9 bytes
- Bit16u panSettings; // 8 bytes
- Bit16u programSettings; // 8 bytes
- Bit16u rhythmMaxTable; // 4 bytes
- Bit16u patchMaxTable; // 16 bytes
- Bit16u systemMaxTable; // 23 bytes
- Bit16u timbreMaxTable; // 72 bytes
-};
-
-enum MemoryRegionType {
- MR_PatchTemp, MR_RhythmTemp, MR_TimbreTemp, MR_Patches, MR_Timbres, MR_System, MR_Display, MR_Reset
-};
-
-enum ReverbMode {
- REVERB_MODE_ROOM,
- REVERB_MODE_HALL,
- REVERB_MODE_PLATE,
- REVERB_MODE_TAP_DELAY
-};
-
-class MemoryRegion {
-private:
- Synth *synth;
- Bit8u *realMemory;
- Bit8u *maxTable;
-public:
- MemoryRegionType type;
- Bit32u startAddr, entrySize, entries;
-
- MemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable, MemoryRegionType useType, Bit32u useStartAddr, Bit32u useEntrySize, Bit32u useEntries) {
- synth = useSynth;
- realMemory = useRealMemory;
- maxTable = useMaxTable;
- type = useType;
- startAddr = useStartAddr;
- entrySize = useEntrySize;
- entries = useEntries;
- }
- int lastTouched(Bit32u addr, Bit32u len) const {
- return (offset(addr) + len - 1) / entrySize;
- }
- int firstTouchedOffset(Bit32u addr) const {
- return offset(addr) % entrySize;
- }
- int firstTouched(Bit32u addr) const {
- return offset(addr) / entrySize;
- }
- Bit32u regionEnd() const {
- return startAddr + entrySize * entries;
- }
- bool contains(Bit32u addr) const {
- return addr >= startAddr && addr < regionEnd();
- }
- int offset(Bit32u addr) const {
- return addr - startAddr;
- }
- Bit32u getClampedLen(Bit32u addr, Bit32u len) const {
- if (addr + len > regionEnd())
- return regionEnd() - addr;
- return len;
- }
- Bit32u next(Bit32u addr, Bit32u len) const {
- if (addr + len > regionEnd()) {
- return regionEnd() - addr;
- }
- return 0;
- }
- Bit8u getMaxValue(int off) const {
- if (maxTable == NULL)
- return 0xFF;
- return maxTable[off % entrySize];
- }
- Bit8u *getRealMemory() const {
- return realMemory;
- }
- bool isReadable() const {
- return getRealMemory() != NULL;
- }
- void read(unsigned int entry, unsigned int off, Bit8u *dst, unsigned int len) const;
- void write(unsigned int entry, unsigned int off, const Bit8u *src, unsigned int len, bool init = false) const;
-};
-
-class PatchTempMemoryRegion : public MemoryRegion {
-public:
- PatchTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_PatchTemp, MT32EMU_MEMADDR(0x030000), sizeof(MemParams::PatchTemp), 9) {}
-};
-class RhythmTempMemoryRegion : public MemoryRegion {
-public:
- RhythmTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_RhythmTemp, MT32EMU_MEMADDR(0x030110), sizeof(MemParams::RhythmTemp), 85) {}
-};
-class TimbreTempMemoryRegion : public MemoryRegion {
-public:
- TimbreTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_TimbreTemp, MT32EMU_MEMADDR(0x040000), sizeof(TimbreParam), 8) {}
-};
-class PatchesMemoryRegion : public MemoryRegion {
-public:
- PatchesMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_Patches, MT32EMU_MEMADDR(0x050000), sizeof(PatchParam), 128) {}
-};
-class TimbresMemoryRegion : public MemoryRegion {
-public:
- TimbresMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_Timbres, MT32EMU_MEMADDR(0x080000), sizeof(MemParams::PaddedTimbre), 64 + 64 + 64 + 64) {}
-};
-class SystemMemoryRegion : public MemoryRegion {
-public:
- SystemMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_System, MT32EMU_MEMADDR(0x100000), sizeof(MemParams::System), 1) {}
-};
-class DisplayMemoryRegion : public MemoryRegion {
-public:
- DisplayMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Display, MT32EMU_MEMADDR(0x200000), MAX_SYSEX_SIZE - 1, 1) {}
-};
-class ResetMemoryRegion : public MemoryRegion {
-public:
- ResetMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Reset, MT32EMU_MEMADDR(0x7F0000), 0x3FFF, 1) {}
-};
-
class ReportHandler {
friend class Synth;
@@ -254,47 +161,6 @@ protected:
virtual void onProgramChanged(int /* partNum */, int /* bankNum */, const char * /* patchName */) {}
};
-/**
- * Used to safely store timestamped MIDI events in a local queue.
- */
-struct MidiEvent {
- Bit32u shortMessageData;
- const Bit8u *sysexData;
- Bit32u sysexLength;
- Bit32u timestamp;
-
- ~MidiEvent();
- void setShortMessage(Bit32u shortMessageData, Bit32u timestamp);
- void setSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp);
-};
-
-/**
- * Simple queue implementation using a ring buffer to store incoming MIDI event before the synth actually processes it.
- * It is intended to:
- * - get rid of prerenderer while retaining graceful partial abortion
- * - add fair emulation of the MIDI interface delays
- * - extend the synth interface with the default implementation of a typical rendering loop.
- * THREAD SAFETY:
- * It is safe to use either in a single thread environment or when there are only two threads - one performs only reading
- * and one performs only writing. More complicated usage requires external synchronisation.
- */
-class MidiEventQueue {
-private:
- MidiEvent *ringBuffer;
- Bit32u ringBufferSize;
- volatile Bit32u startPosition;
- volatile Bit32u endPosition;
-
-public:
- MidiEventQueue(Bit32u ringBufferSize = DEFAULT_MIDI_EVENT_QUEUE_SIZE);
- ~MidiEventQueue();
- void reset();
- bool pushShortMessage(Bit32u shortMessageData, Bit32u timestamp);
- bool pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp);
- const MidiEvent *peekMidiEvent();
- void dropMidiEvent();
-};
-
class Synth {
friend class Part;
friend class RhythmPart;
@@ -335,7 +201,7 @@ private:
volatile Bit32u lastReceivedMIDIEventTimestamp;
volatile Bit32u renderedSampleCount;
- MemParams mt32ram, mt32default;
+ MemParams &mt32ram, &mt32default;
BReverbModel *reverbModels[4];
BReverbModel *reverbModel;
@@ -346,12 +212,6 @@ private:
float outputGain;
float reverbOutputGain;
-#if MT32EMU_USE_FLOAT_SAMPLES
- float effectiveReverbOutputGain;
-#else
- int effectiveOutputGain;
- int effectiveReverbOutputGain;
-#endif
bool reversedStereoEnabled;
@@ -368,11 +228,12 @@ private:
// We emulate this by delaying new MIDI events processing until abortion finishes.
Poly *abortingPoly;
- Bit32u getShortMessageLength(Bit32u msg);
+ Analog *analog;
+
Bit32u addMIDIInterfaceDelay(Bit32u len, Bit32u timestamp);
void produceLA32Output(Sample *buffer, Bit32u len);
- void convertSamplesToOutput(Sample *buffer, Bit32u len, bool reverb);
+ void convertSamplesToOutput(Sample *buffer, Bit32u len);
bool isAbortingPoly() const;
void doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len);
@@ -404,13 +265,20 @@ private:
void newTimbreSet(int partNum, Bit8u timbreGroup, const char patchName[]);
void printDebug(const char *fmt, ...);
+ // partNum should be 0..7 for Part 1..8, or 8 for Rhythm
+ const Part *getPart(unsigned int partNum) const;
+
public:
- static inline Bit16s clipBit16s(Bit32s sample) {
+ static inline Sample clipSampleEx(SampleEx sampleEx) {
+#if MT32EMU_USE_FLOAT_SAMPLES
+ return sampleEx;
+#else
// Clamp values above 32767 to 32767, and values below -32768 to -32768
// FIXME: Do we really need this stuff? I think these branches are very well predicted. Instead, this introduces a chain.
// The version below is actually a bit faster on my system...
- //return ((sample + 0x8000) & ~0xFFFF) ? (sample >> 31) ^ 0x7FFF : (Bit16s)sample;
- return ((-0x8000 <= sample) && (sample <= 0x7FFF)) ? (Bit16s)sample : (sample >> 31) ^ 0x7FFF;
+ //return ((sampleEx + 0x8000) & ~0xFFFF) ? (sampleEx >> 31) ^ 0x7FFF : (Sample)sampleEx;
+ return ((-0x8000 <= sampleEx) && (sampleEx <= 0x7FFF)) ? (Sample)sampleEx : (sampleEx >> 31) ^ 0x7FFF;
+#endif
}
static inline void muteSampleBuffer(Sample *buffer, Bit32u len) {
@@ -426,7 +294,8 @@ public:
#endif
}
- static Bit8u calcSysexChecksum(const Bit8u *data, Bit32u len, Bit8u checksum);
+ static Bit32u getShortMessageLength(Bit32u msg);
+ static Bit8u calcSysexChecksum(const Bit8u *data, const Bit32u len, const Bit8u initChecksum = 0);
// Optionally sets callbacks for reporting various errors, information and debug messages
Synth(ReportHandler *useReportHandler = NULL);
@@ -435,8 +304,12 @@ public:
// Used to initialise the MT-32. Must be called before any other function.
// Returns true if initialization was sucessful, otherwise returns false.
// controlROMImage and pcmROMImage represent Control and PCM ROM images for use by synth.
- // usePartialCount sets the maximum number of partials playing simultaneously for this session.
- bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, unsigned int usePartialCount = DEFAULT_MAX_PARTIALS);
+ // usePartialCount sets the maximum number of partials playing simultaneously for this session (optional).
+ // analogOutputMode sets the mode for emulation of analogue circuitry of the hardware units (optional).
+ bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, unsigned int usePartialCount = DEFAULT_MAX_PARTIALS, AnalogOutputMode analogOutputMode = AnalogOutputMode_COARSE);
+
+ // Overloaded method which opens the synth with default partial count.
+ bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, AnalogOutputMode analogOutputMode);
// Closes the MT-32 and deallocates any memory used by the synthesizer
void close(bool forced = false);
@@ -444,29 +317,34 @@ public:
// All the enqueued events are processed by the synth immediately.
void flushMIDIQueue();
- // Sets size of the internal MIDI event queue.
+ // Sets size of the internal MIDI event queue. The queue size is set to the minimum power of 2 that is greater or equal to the size specified.
// The queue is flushed before reallocation.
- void setMIDIEventQueueSize(Bit32u);
+ // Returns the actual queue size being used.
+ Bit32u setMIDIEventQueueSize(Bit32u);
// Enqueues a MIDI event for subsequent playback.
- // The minimum delay involves the delay introduced while the event is transferred via MIDI interface
+ // The MIDI event will be processed not before the specified timestamp.
+ // The timestamp is measured as the global rendered sample count since the synth was created (at the native sample rate 32000 Hz).
+ // The minimum delay involves emulation of the delay introduced while the event is transferred via MIDI interface
// and emulation of the MCU busy-loop while it frees partials for use by a new Poly.
- // Calls from multiple threads must be synchronised, although,
- // no synchronisation is required with the rendering thread.
+ // Calls from multiple threads must be synchronised, although, no synchronisation is required with the rendering thread.
+ // The methods return false if the MIDI event queue is full and the message cannot be enqueued.
- // The MIDI event will be processed not before the specified timestamp.
- // The timestamp is measured as the global rendered sample count since the synth was created.
+ // Enqueues a single short MIDI message. The message must contain a status byte.
bool playMsg(Bit32u msg, Bit32u timestamp);
+ // Enqueues a single well formed System Exclusive MIDI message.
bool playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp);
- // The MIDI event will be processed ASAP.
+
+ // Overloaded methods for the MIDI events to be processed ASAP.
bool playMsg(Bit32u msg);
bool playSysex(const Bit8u *sysex, Bit32u len);
// WARNING:
// The methods below don't ensure minimum 1-sample delay between sequential MIDI events,
// and a sequence of NoteOn and immediately succeeding NoteOff messages is always silent.
+ // A thread that invokes these methods must be explicitly synchronised with the thread performing sample rendering.
- // Sends a 4-byte MIDI message to the MT-32 for immediate playback.
+ // Sends a short MIDI message to the synth for immediate playback. The message must contain a status byte.
void playMsgNow(Bit32u msg);
void playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity);
@@ -495,12 +373,17 @@ public:
void setMIDIDelayMode(MIDIDelayMode mode);
MIDIDelayMode getMIDIDelayMode() const;
- // Sets output gain factor. Applied to all output samples and unrelated with the synth's Master volume.
+ // Sets output gain factor for synth output channels. Applied to all output samples and unrelated with the synth's Master volume,
+ // it rather corresponds to the gain of the output analog circuitry of the hardware units. However, together with setReverbOutputGain()
+ // it offers to the user a capability to control the gain of reverb and non-reverb output channels independently.
// Ignored in DACInputMode_PURE
void setOutputGain(float);
float getOutputGain() const;
- // Sets output gain factor for the reverb wet output. setOutputGain() doesn't change reverb output gain.
+ // Sets output gain factor for the reverb wet output channels. It rather corresponds to the gain of the output
+ // analog circuitry of the hardware units. However, together with setOutputGain() it offers to the user a capability
+ // to control the gain of reverb and non-reverb output channels independently.
+ //
// Note: We're currently emulate CM-32L/CM-64 reverb quite accurately and the reverb output level closely
// corresponds to the level of digital capture. Although, according to the CM-64 PCB schematic,
// there is a difference in the reverb analogue circuit, and the resulting output gain is 0.68
@@ -512,12 +395,21 @@ public:
void setReversedStereoEnabled(bool enabled);
bool isReversedStereoEnabled();
- // Renders samples to the specified output stream.
- // The length is in frames, not bytes (in 16-bit stereo,
- // one frame is 4 bytes).
+ // Returns actual sample rate used in emulation of stereo analog circuitry of hardware units.
+ // See comment for render() below.
+ unsigned int getStereoOutputSampleRate() const;
+
+ // Renders samples to the specified output stream as if they were sampled at the analog stereo output.
+ // When AnalogOutputMode is set to ACCURATE, the output signal is upsampled to 48 kHz in order
+ // to retain emulation accuracy in whole audible frequency spectra. Otherwise, native digital signal sample rate is retained.
+ // getStereoOutputSampleRate() can be used to query actual sample rate of the output signal.
+ // The length is in frames, not bytes (in 16-bit stereo, one frame is 4 bytes).
void render(Sample *stream, Bit32u len);
- // Renders samples to the specified output streams (any or all of which may be NULL).
+ // Renders samples to the specified output streams as if they appeared at the DAC entrance.
+ // No further processing performed in analog circuitry emulation is applied to the signal.
+ // NULL may be specified in place of any or all of the stream buffers.
+ // The length is in samples, not bytes.
void renderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len);
// Returns true when there is at least one active partial, otherwise false.
@@ -526,15 +418,28 @@ public:
// Returns true if hasActivePartials() returns true, or reverb is (somewhat unreliably) detected as being active.
bool isActive() const;
- const Partial *getPartial(unsigned int partialNum) const;
-
// Returns the maximum number of partials playing simultaneously.
unsigned int getPartialCount() const;
- void readMemory(Bit32u addr, Bit32u len, Bit8u *data);
+ // Fills in current states of all the parts into the array provided. The array must have at least 9 entries to fit values for all the parts.
+ // If the value returned for a part is true, there is at least one active non-releasing partial playing on this part.
+ // This info is useful in emulating behaviour of LCD display of the hardware units.
+ void getPartStates(bool *partStates) const;
- // partNum should be 0..7 for Part 1..8, or 8 for Rhythm
- const Part *getPart(unsigned int partNum) const;
+ // Fills in current states of all the partials into the array provided. The array must be large enough to accommodate states of all the partials.
+ void getPartialStates(PartialState *partialStates) const;
+
+ // Fills in information about currently playing notes on the specified part into the arrays provided. The arrays must be large enough
+ // to accommodate data for all the playing notes. The maximum number of simultaneously playing notes cannot exceed the number of partials.
+ // Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm.
+ // Returns the number of currently playing notes on the specified part.
+ unsigned int getPlayingNotes(unsigned int partNumber, Bit8u *keys, Bit8u *velocities) const;
+
+ // Returns name of the patch set on the specified part.
+ // Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm.
+ const char *getPatchName(unsigned int partNumber) const;
+
+ void readMemory(Bit32u addr, Bit32u len, Bit8u *data);
};
}
diff --git a/audio/softsynth/mt32/TVA.cpp b/audio/softsynth/mt32/TVA.cpp
index 3fefb791f2..894e53f14a 100644
--- a/audio/softsynth/mt32/TVA.cpp
+++ b/audio/softsynth/mt32/TVA.cpp
@@ -23,6 +23,7 @@
#include "mt32emu.h"
#include "mmath.h"
+#include "internals.h"
namespace MT32Emu {
diff --git a/audio/softsynth/mt32/TVF.cpp b/audio/softsynth/mt32/TVF.cpp
index bf8d50a7c9..164cf2b4cb 100644
--- a/audio/softsynth/mt32/TVF.cpp
+++ b/audio/softsynth/mt32/TVF.cpp
@@ -19,6 +19,7 @@
#include "mt32emu.h"
#include "mmath.h"
+#include "internals.h"
namespace MT32Emu {
diff --git a/audio/softsynth/mt32/TVP.cpp b/audio/softsynth/mt32/TVP.cpp
index 374646e5f1..a8003d96dc 100644
--- a/audio/softsynth/mt32/TVP.cpp
+++ b/audio/softsynth/mt32/TVP.cpp
@@ -19,6 +19,7 @@
//#include <cstdlib>
#include "mt32emu.h"
+#include "internals.h"
namespace MT32Emu {
diff --git a/audio/softsynth/mt32/Tables.cpp b/audio/softsynth/mt32/Tables.cpp
index ae9f11fff0..7e165b5a7a 100644
--- a/audio/softsynth/mt32/Tables.cpp
+++ b/audio/softsynth/mt32/Tables.cpp
@@ -16,14 +16,15 @@
*/
//#include <cmath>
-//#include <cstdlib>
-//#include <cstring>
#include "mt32emu.h"
#include "mmath.h"
+#include "Tables.h"
namespace MT32Emu {
+// UNUSED: const int MIDDLEC = 60;
+
const Tables &Tables::getInstance() {
static const Tables instance;
return instance;
diff --git a/audio/softsynth/mt32/Tables.h b/audio/softsynth/mt32/Tables.h
index e7b97af515..8865c7fac8 100644
--- a/audio/softsynth/mt32/Tables.h
+++ b/audio/softsynth/mt32/Tables.h
@@ -20,24 +20,11 @@
namespace MT32Emu {
-// Sample rate to use in mixing. With the progress of development, we've found way too many thing dependent.
-// In order to achieve further advance in emulation accuracy, sample rate made fixed throughout the emulator.
-// The output from the synth is supposed to be resampled to convert the sample rate.
-const unsigned int SAMPLE_RATE = 32000;
-
-// MIDI interface data transfer rate in samples. Used to simulate the transfer delay.
-const double MIDI_DATA_TRANSFER_RATE = (double)SAMPLE_RATE / 31250.0 * 8.0;
-
-const float CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR = 0.68f;
-
-const int MIDDLEC = 60;
-
-class Synth;
-
class Tables {
private:
Tables();
Tables(Tables &);
+ ~Tables() {}
public:
static const Tables &getInstance();
diff --git a/audio/softsynth/mt32/Types.h b/audio/softsynth/mt32/Types.h
new file mode 100644
index 0000000000..934b1a1173
--- /dev/null
+++ b/audio/softsynth/mt32/Types.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
+ * Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MT32EMU_TYPES_H
+#define MT32EMU_TYPES_H
+
+namespace MT32Emu {
+
+typedef unsigned int Bit32u;
+typedef signed int Bit32s;
+typedef unsigned short int Bit16u;
+typedef signed short int Bit16s;
+typedef unsigned char Bit8u;
+typedef signed char Bit8s;
+
+#if MT32EMU_USE_FLOAT_SAMPLES
+typedef float Sample;
+typedef float SampleEx;
+#else
+typedef Bit16s Sample;
+typedef Bit32s SampleEx;
+#endif
+
+}
+
+#endif
diff --git a/audio/softsynth/mt32/internals.h b/audio/softsynth/mt32/internals.h
new file mode 100644
index 0000000000..ef56819a42
--- /dev/null
+++ b/audio/softsynth/mt32/internals.h
@@ -0,0 +1,83 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
+ * Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MT32EMU_INTERNALS_H
+#define MT32EMU_INTERNALS_H
+
+// Debugging
+
+// 0: Standard debug output is not stamped with the rendered sample count
+// 1: Standard debug output is stamped with the rendered sample count
+// NOTE: The "samplestamp" corresponds to the end of the last completed rendering run.
+// This is important to bear in mind for debug output that occurs during a run.
+#define MT32EMU_DEBUG_SAMPLESTAMPS 0
+
+// 0: No debug output for initialisation progress
+// 1: Debug output for initialisation progress
+#define MT32EMU_MONITOR_INIT 0
+
+// 0: No debug output for MIDI events
+// 1: Debug output for weird MIDI events
+#define MT32EMU_MONITOR_MIDI 0
+
+// 0: No debug output for note on/off
+// 1: Basic debug output for note on/off
+// 2: Comprehensive debug output for note on/off
+#define MT32EMU_MONITOR_INSTRUMENTS 0
+
+// 0: No debug output for partial allocations
+// 1: Show partial stats when an allocation fails
+// 2: Show partial stats with every new poly
+// 3: Show individual partial allocations/deactivations
+#define MT32EMU_MONITOR_PARTIALS 0
+
+// 0: No debug output for sysex
+// 1: Basic debug output for sysex
+#define MT32EMU_MONITOR_SYSEX 0
+
+// 0: No debug output for sysex writes to the timbre areas
+// 1: Debug output with the name and location of newly-written timbres
+// 2: Complete dump of timbre parameters for newly-written timbres
+#define MT32EMU_MONITOR_TIMBRES 0
+
+// 0: No TVA/TVF-related debug output.
+// 1: Shows changes to TVA/TVF target, increment and phase.
+#define MT32EMU_MONITOR_TVA 0
+#define MT32EMU_MONITOR_TVF 0
+
+// Configuration
+
+// If non-zero, deletes reverb buffers that are not in use to save memory.
+// If zero, keeps reverb buffers for all modes around all the time to avoid allocating/freeing in the critical path.
+#define MT32EMU_REDUCE_REVERB_MEMORY 1
+
+// 0: Maximum speed at the cost of a bit lower emulation accuracy.
+// 1: Maximum achievable emulation accuracy.
+#define MT32EMU_BOSS_REVERB_PRECISE_MODE 0
+
+#include "Structures.h"
+#include "Tables.h"
+#include "Poly.h"
+#include "LA32Ramp.h"
+#include "LA32WaveGenerator.h"
+#include "TVA.h"
+#include "TVP.h"
+#include "TVF.h"
+#include "Partial.h"
+#include "Part.h"
+
+#endif
diff --git a/audio/softsynth/mt32/module.mk b/audio/softsynth/mt32/module.mk
index 1c8aa125ab..f966da8d08 100644
--- a/audio/softsynth/mt32/module.mk
+++ b/audio/softsynth/mt32/module.mk
@@ -1,6 +1,7 @@
MODULE := audio/softsynth/mt32
MODULE_OBJS := \
+ Analog.o \
BReverbModel.o \
LA32Ramp.o \
LA32WaveGenerator.o \
diff --git a/audio/softsynth/mt32/mt32emu.h b/audio/softsynth/mt32/mt32emu.h
index d738a5de35..1574c08f0d 100644
--- a/audio/softsynth/mt32/mt32emu.h
+++ b/audio/softsynth/mt32/mt32emu.h
@@ -18,63 +18,20 @@
#ifndef MT32EMU_MT32EMU_H
#define MT32EMU_MT32EMU_H
-// Debugging
-
-// 0: Standard debug output is not stamped with the rendered sample count
-// 1: Standard debug output is stamped with the rendered sample count
-// NOTE: The "samplestamp" corresponds to the end of the last completed rendering run.
-// This is important to bear in mind for debug output that occurs during a run.
-#define MT32EMU_DEBUG_SAMPLESTAMPS 0
-
-// 0: No debug output for initialisation progress
-// 1: Debug output for initialisation progress
-#define MT32EMU_MONITOR_INIT 0
-
-// 0: No debug output for MIDI events
-// 1: Debug output for weird MIDI events
-#define MT32EMU_MONITOR_MIDI 0
-
-// 0: No debug output for note on/off
-// 1: Basic debug output for note on/off
-// 2: Comprehensive debug output for note on/off
-#define MT32EMU_MONITOR_INSTRUMENTS 0
-
-// 0: No debug output for partial allocations
-// 1: Show partial stats when an allocation fails
-// 2: Show partial stats with every new poly
-// 3: Show individual partial allocations/deactivations
-#define MT32EMU_MONITOR_PARTIALS 0
-
-// 0: No debug output for sysex
-// 1: Basic debug output for sysex
-#define MT32EMU_MONITOR_SYSEX 0
-
-// 0: No debug output for sysex writes to the timbre areas
-// 1: Debug output with the name and location of newly-written timbres
-// 2: Complete dump of timbre parameters for newly-written timbres
-#define MT32EMU_MONITOR_TIMBRES 0
-
-// 0: No TVA/TVF-related debug output.
-// 1: Shows changes to TVA/TVF target, increment and phase.
-#define MT32EMU_MONITOR_TVA 0
-#define MT32EMU_MONITOR_TVF 0
-
// Configuration
-// If non-zero, deletes reverb buffers that are not in use to save memory.
-// If zero, keeps reverb buffers for all modes around all the time to avoid allocating/freeing in the critical path.
-#define MT32EMU_REDUCE_REVERB_MEMORY 1
-
-// 0: Maximum speed at the cost of a bit lower emulation accuracy.
-// 1: Maximum achievable emulation accuracy.
-#define MT32EMU_BOSS_REVERB_PRECISE_MODE 0
-
// 0: Use 16-bit signed samples and refined wave generator based on logarithmic fixed-point computations and LUTs. Maximum emulation accuracy and speed.
// 1: Use float samples in the wave generator and renderer. Maximum output quality and minimum noise.
#define MT32EMU_USE_FLOAT_SAMPLES 0
namespace MT32Emu
{
+// Sample rate to use in mixing. With the progress of development, we've found way too many thing dependent.
+// In order to achieve further advance in emulation accuracy, sample rate made fixed throughout the emulator,
+// except the emulation of analogue path.
+// The output from the synth is supposed to be resampled externally in order to convert to the desired sample rate.
+const unsigned int SAMPLE_RATE = 32000;
+
// The default value for the maximum number of partials playing simultaneously.
const unsigned int DEFAULT_MAX_PARTIALS = 32;
@@ -97,17 +54,7 @@ const unsigned int MAX_SAMPLES_PER_RUN = 4096;
const unsigned int DEFAULT_MIDI_EVENT_QUEUE_SIZE = 1024;
}
-#include "Structures.h"
-#include "common/file.h"
-#include "Tables.h"
-#include "Poly.h"
-#include "LA32Ramp.h"
-#include "LA32WaveGenerator.h"
-#include "TVA.h"
-#include "TVP.h"
-#include "TVF.h"
-#include "Partial.h"
-#include "Part.h"
+#include "Types.h"
#include "ROMInfo.h"
#include "Synth.h"
diff --git a/audio/timestamp.cpp b/audio/timestamp.cpp
index 1ce971631c..63752812e1 100644
--- a/audio/timestamp.cpp
+++ b/audio/timestamp.cpp
@@ -39,12 +39,10 @@ Timestamp::Timestamp(uint ms, uint fr) {
Timestamp::Timestamp(uint s, uint frames, uint fr) {
assert(fr > 0);
- _secs = s;
+ _secs = s + (frames / fr);
_framerateFactor = 1000 / Common::gcd<uint>(1000, fr);
_framerate = fr * _framerateFactor;
- _numFrames = frames * _framerateFactor;
-
- normalize();
+ _numFrames = (frames % fr) * _framerateFactor;
}
Timestamp Timestamp::convertToFramerate(uint newFramerate) const {
diff --git a/devtools/credits.pl b/devtools/credits.pl
index 1c2ece80ed..7dc954a6a7 100755
--- a/devtools/credits.pl
+++ b/devtools/credits.pl
@@ -791,6 +791,8 @@ begin_credits("Credits");
begin_section("ZVision");
add_person("Adrian Astley", "RichieSams", "");
+ add_person("Filippos Karapetis", "[md5]", "");
+ add_person("Anton Yarcev", "Zidane", "");
end_section();
end_section();
@@ -1092,6 +1094,12 @@ begin_credits("Credits");
add_person("V&iacute;ctor Gonz&aacute;lez", "IlDucci", "Soltys Spanish translation");
add_person("Alejandro G&oacute;mez de la Mu&ntilde;oza", "TheFireRed", "Soltys Spanish translation");
end_section();
+ begin_section("CGE2");
+ add_person("Arnaud Boutonn&eacute;", "Strangerke", "Sfinx English translation");
+ add_person("Thierry Crozat", "criezy", "Sfinx English translation");
+ add_person("Peter Bozs&oacute;", "uruk", "Sfinx English translation editor");
+ add_person("Ryan Clark", "", "Sfinx English translation editor");
+ end_section();
begin_section("Drascula");
add_person("Thierry Crozat", "criezy", "Improve French translation");
end_section();
diff --git a/engines/access/access.cpp b/engines/access/access.cpp
index 6ad1b22408..7f59ae7ad6 100644
--- a/engines/access/access.cpp
+++ b/engines/access/access.cpp
@@ -41,6 +41,7 @@ AccessEngine::AccessEngine(OSystem *syst, const AccessGameDescription *gameDesc)
_events = nullptr;
_files = nullptr;
_inventory = nullptr;
+ _midi = nullptr;
_player = nullptr;
_room = nullptr;
_screen = nullptr;
@@ -92,6 +93,7 @@ AccessEngine::AccessEngine(OSystem *syst, const AccessGameDescription *gameDesc)
_vidX = _vidY = 0;
_cheatFl = false;
_restartFl = false;
+ _printEnd = 0;
}
AccessEngine::~AccessEngine() {
@@ -220,12 +222,13 @@ void AccessEngine::speakText(ASurface *s, const Common::String &msg) {
_events->clearEvents();
while (!shouldQuit()) {
_sound->freeSounds();
- Resource *sound = _sound->loadSound(_narateFile + 99, _sndSubFile);
- _sound->_soundTable.push_back(SoundEntry(sound, 1));
+ _sound->loadSoundTable(0, _narateFile + 99, _sndSubFile);
_sound->playSound(0);
- _scripts->cmdFreeSound();
- _events->pollEvents();
+ while(_sound->isSFXPlaying() && !shouldQuit())
+ _events->pollEvents();
+
+ _scripts->cmdFreeSound();
if (_events->isKeyMousePressed()) {
_sndSubFile += soundsLeft;
@@ -254,9 +257,11 @@ void AccessEngine::speakText(ASurface *s, const Common::String &msg) {
Resource *res = _sound->loadSound(_narateFile + 99, _sndSubFile);
_sound->_soundTable.push_back(SoundEntry(res, 1));
_sound->playSound(0);
- _scripts->cmdFreeSound();
- _events->pollEvents();
+ while(_sound->isSFXPlaying() && !shouldQuit())
+ _events->pollEvents();
+
+ _scripts->cmdFreeSound();
if (_events->_leftButton) {
_events->debounceLeft();
diff --git a/engines/access/access.h b/engines/access/access.h
index a082b969c4..be007e0cb8 100644
--- a/engines/access/access.h
+++ b/engines/access/access.h
@@ -191,7 +191,6 @@ public:
bool _canSaveLoad;
Resource *_establish;
- int _et;
int _printEnd;
int _txtPages;
int _narateFile;
diff --git a/engines/access/amazon/amazon_game.cpp b/engines/access/amazon/amazon_game.cpp
index 933a98aded..4c9df7b8ff 100644
--- a/engines/access/amazon/amazon_game.cpp
+++ b/engines/access/amazon/amazon_game.cpp
@@ -61,9 +61,16 @@ AmazonEngine::AmazonEngine(OSystem *syst, const AccessGameDescription *gameDesc)
_helpTbl[1] = _help2;
_helpTbl[2] = _help3;
+ _chapter = 0;
+ _rawInactiveX = _rawInactiveY = 0;
+ _inactiveYOff = 0;
+ _hintLevel = 0;
+ _updateChapter = 0;
+ _oldTitleChapter = 0;
+ _iqValue = 0;
+
_chapterCells.push_back(CellIdent(0, 96, 17));
_inactive._spritesPtr = nullptr;
- _inactive._altSpritesPtr = nullptr;
_inactive._flags = _inactive._frameNumber = _inactive._offsetY = 0;
_inactive._position = Common::Point(0, 0);
}
@@ -261,7 +268,6 @@ void AmazonEngine::doEstablish(int screenId, int estabIndex) {
_screen->_maxChars = 37;
_screen->_printOrg = _screen->_printStart = Common::Point(48, 35);
loadEstablish(estabIndex);
- _et = estabIndex;
uint16 msgOffset;
if (!isCD())
msgOffset = READ_LE_UINT16(_establish->data() + (estabIndex * 2));
@@ -522,8 +528,8 @@ void AmazonEngine::startChapter(int chapter) {
_sound->freeSounds();
if (isCD()) {
- _sound->_soundTable.push_back(SoundEntry(_sound->loadSound(115, 0), 1));
- _sound->_soundTable.push_back(SoundEntry(_sound->loadSound(115, 1), 1));
+ _sound->loadSoundTable(0, 115, 0);
+ _sound->loadSoundTable(1, 115, 1);
_sound->playSound(0);
_sound->playSound(1);
@@ -552,7 +558,7 @@ void AmazonEngine::startChapter(int chapter) {
// Show chapter screen
_files->loadScreen(96, 15);
- _buffer2.copyFrom(*_screen);
+ _buffer2.blitFrom(*_screen);
const int *chapImg = &CHAPTER_TABLE[_chapter - 1][0];
_screen->plotImage(_objectsTable[0], _chapter - 1,
@@ -583,14 +589,14 @@ void AmazonEngine::startChapter(int chapter) {
_screen->clearBuffer();
_files->loadScreen(96, 16);
- _buffer2.copyFrom(*_screen);
+ _buffer2.blitFrom(*_screen);
_screen->plotImage(_objectsTable[0], chapImg[0], Common::Point(90, 7));
_midi->newMusic(7, 1);
_midi->newMusic(34, 0);
_screen->forceFadeIn();
- _buffer2.copyFrom(*_screen);
+ _buffer2.blitFrom(*_screen);
_fonts._charSet._lo = 1;
_fonts._charSet._hi = 10;
@@ -670,7 +676,7 @@ void AmazonEngine::dead(int deathId) {
_files->_setPaletteFlag = false;
_files->loadScreen(94, 0);
_files->_setPaletteFlag = true;
- _buffer2.copyFrom(*_screen);
+ _buffer2.blitFrom(*_screen);
if (!isDemo() || deathId != 10) {
for (int i = 0; i < 3; ++i) {
diff --git a/engines/access/amazon/amazon_logic.cpp b/engines/access/amazon/amazon_logic.cpp
index 436a875688..6dffb85e5e 100644
--- a/engines/access/amazon/amazon_logic.cpp
+++ b/engines/access/amazon/amazon_logic.cpp
@@ -106,8 +106,8 @@ void CampScene::mWhileDoOpen() {
_vm->_files->_setPaletteFlag = false;
_vm->_files->loadScreen(1, 2);
- _vm->_buffer2.copyFrom(*_vm->_screen);
- _vm->_buffer1.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
// Load animation data
_vm->_animation->freeAnimationData();
@@ -317,8 +317,8 @@ void Opening::doTitle() {
_vm->_events->hideCursor();
if (!_vm->isDemo()) {
- _vm->_sound->queueSound(0, 98, 30);
- _vm->_sound->queueSound(1, 98, 8);
+ _vm->_sound->loadSoundTable(0, 98, 30);
+ _vm->_sound->loadSoundTable(1, 98, 8);
_vm->_files->_setPaletteFlag = false;
_vm->_files->loadScreen(0, 3);
@@ -341,19 +341,16 @@ void Opening::doTitle() {
_vm->_objectsTable[0] = new SpriteResource(_vm, spriteData);
delete spriteData;
- _vm->_sound->playSound(1);
-
_vm->_files->_setPaletteFlag = false;
_vm->_files->loadScreen(0, 4);
_vm->_sound->playSound(1);
_vm->_buffer2.copyFrom(*_vm->_screen);
_vm->_buffer1.copyFrom(*_vm->_screen);
- _vm->_sound->playSound(1);
const int COUNTDOWN[6] = { 2, 0x80, 1, 0x7d, 0, 0x87 };
for (_pCount = 0; _pCount < 3 && !_vm->shouldQuit(); ++_pCount) {
- _vm->_buffer2.copyFrom(_vm->_buffer1);
+ _vm->_buffer2.blitFrom(_vm->_buffer1);
int id = COUNTDOWN[_pCount * 2];
int xp = COUNTDOWN[_pCount * 2 + 1];
_vm->_buffer2.plotImage(_vm->_objectsTable[0], id, Common::Point(xp, 71));
@@ -385,8 +382,8 @@ void Opening::doTitle() {
_vm->_files->_setPaletteFlag = false;
_vm->_files->loadScreen(0, 5);
- _vm->_buffer2.copyFrom(*_vm->_screen);
- _vm->_buffer1.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
screen.forceFadeIn();
_vm->_midi->newMusic(1, 0);
_vm->_events->_vbCount = 700;
@@ -493,55 +490,62 @@ void Opening::doTent() {
_vm->_screen->setDisplayScan();
_vm->_screen->forceFadeOut();
_vm->_events->hideCursor();
- _vm->_sound->_soundTable.push_back(SoundEntry(_vm->_sound->loadSound(98, 39), 1));
- _vm->_sound->_soundTable.push_back(SoundEntry(_vm->_sound->loadSound(98, 14), 1));
- _vm->_sound->_soundTable.push_back(SoundEntry(_vm->_sound->loadSound(98, 15), 1));
- _vm->_sound->_soundTable.push_back(SoundEntry(_vm->_sound->loadSound(98, 16), 1));
- _vm->_sound->_soundTable.push_back(SoundEntry(_vm->_sound->loadSound(98, 31), 2));
- _vm->_sound->_soundTable.push_back(SoundEntry(_vm->_sound->loadSound(98, 52), 2));
+ _vm->_sound->loadSoundTable(0, 98, 39);
+ _vm->_sound->loadSoundTable(1, 98, 14);
+ _vm->_sound->loadSoundTable(2, 98, 15);
+ _vm->_sound->loadSoundTable(3, 98, 16);
+ _vm->_sound->loadSoundTable(4, 98, 31, 2);
+ _vm->_sound->loadSoundTable(5, 98, 52, 2);
_vm->_sound->playSound(0);
_vm->_files->_setPaletteFlag = false;
_vm->_files->loadScreen(2, 0);
- _vm->_buffer2.copyFrom(*_vm->_screen);
- _vm->_buffer1.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
_vm->_screen->forceFadeIn();
_vm->_video->setVideo(_vm->_screen, Common::Point(126, 73), FileIdent(2, 1), 10);
+ int previousFrame = -1;
while (!_vm->shouldQuit() && !_vm->_video->_videoEnd) {
_vm->_video->playVideo();
- if ((_vm->_video->_videoFrame == 32) || (_vm->_video->_videoFrame == 34))
- _vm->_sound->playSound(4);
- else if (_vm->_video->_videoFrame == 36) {
- if (step != 2) {
- _vm->_sound->playSound(2);
- step = 2;
- }
- } else if (_vm->_video->_videoFrame == 18) {
- if (step != 1) {
- _vm->_midi->newMusic(73, 1);
- _vm->_midi->newMusic(11, 0);
- step = 1;
- _vm->_sound->playSound(1);
+ if (previousFrame != _vm->_video->_videoFrame) {
+ previousFrame = _vm->_video->_videoFrame;
+
+ if ((_vm->_video->_videoFrame == 32) || (_vm->_video->_videoFrame == 34))
+ _vm->_sound->playSound(4);
+ else if (_vm->_video->_videoFrame == 36) {
+ if (step != 2) {
+ _vm->_sound->playSound(2);
+ step = 2;
+ }
+ } else if (_vm->_video->_videoFrame == 18) {
+ if (step != 1) {
+ _vm->_midi->newMusic(73, 1);
+ _vm->_midi->newMusic(11, 0);
+ step = 1;
+ _vm->_sound->playSound(1);
+ }
}
}
-
_vm->_events->pollEventsAndWait();
}
_vm->_sound->playSound(5);
_vm->_video->setVideo(_vm->_screen, Common::Point(43, 11), FileIdent(2, 2), 10);
+ previousFrame = -1;
while (!_vm->shouldQuit() && !_vm->_video->_videoEnd) {
_vm->_video->playVideo();
- if (_vm->_video->_videoFrame == 26) {
- _vm->_sound->playSound(5);
- } else if (_vm->_video->_videoFrame == 15) {
- if (step !=3) {
- _vm->_sound->playSound(3);
- step = 3;
+ if (previousFrame != _vm->_video->_videoFrame) {
+ previousFrame = _vm->_video->_videoFrame;
+ if (_vm->_video->_videoFrame == 26) {
+ _vm->_sound->playSound(5);
+ } else if (_vm->_video->_videoFrame == 15) {
+ if (step !=3) {
+ _vm->_sound->playSound(3);
+ step = 3;
+ }
}
}
-
_vm->_events->pollEventsAndWait();
}
@@ -1035,7 +1039,7 @@ void Guard::setHorizontalCode() {
if (_bottomRight.x < screen._orgX1)
_gCode2 |= 8;
- else if (_bottomRight.y > screen._orgX2)
+ else if (_bottomRight.x > screen._orgX2)
_gCode2 |= 2;
}
@@ -1276,8 +1280,8 @@ void Cast::doCast(int param1) {
_vm->_files->_setPaletteFlag = false;
_vm->_files->loadScreen(58, 1);
- _vm->_buffer2.copyFrom(*_vm->_screen);
- _vm->_buffer1.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
_xTrack = 0;
_yTrack = -6;
@@ -1319,7 +1323,7 @@ void Cast::doCast(int param1) {
while (!_vm->shouldQuit()) {
_vm->_images.clear();
pan();
- _vm->_buffer2.copyFrom(_vm->_buffer1);
+ _vm->_buffer2.blitFrom(_vm->_buffer1);
_vm->_newRects.clear();
_vm->plotList();
_vm->copyBlocks();
@@ -1371,6 +1375,18 @@ River::River(AmazonEngine *vm) : PannedScene(vm) {
_deathCount = 0;
_oldScrollCol = 0;
_maxHits = 0;
+ _mapPtr = nullptr;
+ _canoeMoveCount = 0;
+ _canoeVXPos = 0;
+ _canoeFrame = 0;
+ _canoeDir = 0;
+ _canoeLane = 0;
+ _canoeYPos = 0;
+ _hitCount = 0;
+ _riverIndex = 0;
+ _topList = _botList = nullptr;
+ _deathType = 0;
+ _hitSafe = 0;
}
void River::setRiverPan() {
@@ -1410,7 +1426,7 @@ void River::initRiver() {
_vm->_files->_setPaletteFlag = false;
_vm->_files->loadScreen(95, 4);
- _vm->_buffer2.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
screen.restorePalette();
screen.setBufferScan();
@@ -1480,11 +1496,11 @@ void River::initRiver() {
_maxHits = 2 - _vm->_riverFlag;
_saveRiver = false;
- Font &font2 = _vm->_fonts._font2;
- font2._fontColors[0] = 0;
- font2._fontColors[1] = 33;
- font2._fontColors[2] = 34;
- font2._fontColors[3] = 35;
+ // Set font colors for drawing using font2
+ Font::_fontColors[0] = 0;
+ Font::_fontColors[1] = 33;
+ Font::_fontColors[2] = 34;
+ Font::_fontColors[3] = 35;
}
void River::resetPositions() {
@@ -1510,8 +1526,6 @@ void River::checkRiverPan() {
}
bool River::riverJumpTest() {
- Screen &screen = *_vm->_screen;
-
if (_vm->_scrollCol == 120 || _vm->_scrollCol == 60 || _vm->_scrollCol == 0) {
int val = *++_mapPtr;
if (val == 0xFF)
@@ -1744,7 +1758,7 @@ void River::mWhileDownRiver() {
screen.savePalette();
if (!_vm->isDemo())
_vm->_files->loadScreen(95, 4);
- _vm->_buffer2.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
screen.restorePalette();
screen.setPalette();
screen.setBufferScan();
@@ -1909,7 +1923,6 @@ void River::synchronize(Common::Serializer &s) {
if (_vm->_player->_roomNumber == 45) {
if (s.isSaving()) {
// Set river properties to be saved out
- Screen &screen = *_vm->_screen;
_rScrollRow = _vm->_scrollRow;
_rScrollCol = _vm->_scrollCol;
_rScrollX = _vm->_scrollX;
diff --git a/engines/access/amazon/amazon_logic.h b/engines/access/amazon/amazon_logic.h
index a1fb4eef77..0d962483e6 100644
--- a/engines/access/amazon/amazon_logic.h
+++ b/engines/access/amazon/amazon_logic.h
@@ -242,6 +242,8 @@ public:
class InactivePlayer : public ImageEntry {
public:
SpriteResource *_altSpritesPtr;
+
+ InactivePlayer() { _altSpritesPtr = nullptr; }
};
} // End of namespace Amazon
diff --git a/engines/access/amazon/amazon_scripts.cpp b/engines/access/amazon/amazon_scripts.cpp
index 633188e4dd..92acb3686d 100644
--- a/engines/access/amazon/amazon_scripts.cpp
+++ b/engines/access/amazon/amazon_scripts.cpp
@@ -38,7 +38,7 @@ AmazonScripts::AmazonScripts(AccessEngine *vm) : Scripts(vm) {
void AmazonScripts::cLoop() {
searchForSequence();
_vm->_images.clear();
- _vm->_buffer2.copyFrom(_vm->_buffer1);
+ _vm->_buffer2.blitFrom(_vm->_buffer1);
_vm->_oldRects.clear();
_vm->_scripts->executeScript();
_vm->plotList1();
@@ -51,8 +51,8 @@ void AmazonScripts::mWhile1() {
_vm->_events->hideCursor();
_vm->_files->loadScreen(14, 0);
- _vm->_buffer2.copyFrom(*_vm->_screen);
- _vm->_buffer1.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
_vm->_events->showCursor();
_vm->_screen->setIconPalette();
@@ -86,8 +86,8 @@ void AmazonScripts::mWhile1() {
_vm->_files->loadScreen(14, 1);
_vm->_screen->setPalette();
- _vm->_buffer2.copyFrom(*_vm->_screen);
- _vm->_buffer1.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
_vm->_events->showCursor();
_vm->_screen->setIconPalette();
@@ -95,7 +95,7 @@ void AmazonScripts::mWhile1() {
_vm->_oldRects.clear();
_sequence = 2200;
- _vm->_sound->queueSound(0, 14, 15);
+ _vm->_sound->loadSoundTable(0, 14, 15);
do {
cLoop();
@@ -107,8 +107,8 @@ void AmazonScripts::mWhile1() {
_vm->_files->loadScreen(14, 2);
_vm->_screen->setPalette();
- _vm->_buffer2.copyFrom(*_vm->_screen);
- _vm->_buffer1.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
_vm->_events->showCursor();
_vm->_screen->setIconPalette();
@@ -138,8 +138,8 @@ void AmazonScripts::mWhile1() {
_vm->_files->loadScreen(14, 3);
_vm->_screen->setPalette();
- _vm->_buffer2.copyFrom(*_vm->_screen);
- _vm->_buffer1.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
_vm->_events->showCursor();
_vm->_screen->setIconPalette();
@@ -159,8 +159,8 @@ void AmazonScripts::mWhile2() {
_vm->_events->hideCursor();
_vm->_files->loadScreen(14, 0);
- _vm->_buffer2.copyFrom(*_vm->_screen);
- _vm->_buffer1.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
_vm->_events->showCursor();
_vm->_screen->setIconPalette();
@@ -190,8 +190,8 @@ void AmazonScripts::mWhile2() {
_vm->_files->loadScreen(14, 3);
_vm->_screen->setPalette();
- _vm->_buffer2.copyFrom(*_vm->_screen);
- _vm->_buffer1.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
_vm->_events->showCursor();
_vm->_screen->setIconPalette();
@@ -240,8 +240,8 @@ void AmazonScripts::loadBackground(int param1, int param2) {
_vm->_files->_setPaletteFlag = false;
_vm->_files->loadScreen(param1, param2);
- _vm->_buffer2.copyFrom(*_vm->_screen);
- _vm->_buffer1.copyFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
_vm->_screen->forceFadeIn();
}
diff --git a/engines/access/animation.cpp b/engines/access/animation.cpp
index 548e7db02d..14d7c0d4cc 100644
--- a/engines/access/animation.cpp
+++ b/engines/access/animation.cpp
@@ -310,9 +310,7 @@ Animation *AnimationManager::setAnimation(int animId) {
anim->_countdownTicks = anim->_initialTicks;
anim->_frameNumber = 0;
- anim->_currentLoopCount = (anim->_type != 3 && anim->_type != 4) ? 0 :
- anim->_loopCount;
- anim->_field10 = 0;
+ anim->_currentLoopCount = (anim->_type != 3 && anim->_type != 4) ? 0 : anim->_loopCount;
return anim;
}
diff --git a/engines/access/animation.h b/engines/access/animation.h
index 722f5430ab..72621c4d11 100644
--- a/engines/access/animation.h
+++ b/engines/access/animation.h
@@ -106,7 +106,6 @@ public:
int _loopCount;
int _countdownTicks;
int _currentLoopCount;
- int _field10;
public:
Animation(AccessEngine *vm, Common::SeekableReadStream *stream);
~Animation();
diff --git a/engines/access/asurface.cpp b/engines/access/asurface.cpp
index 38af7add00..5f4372d5af 100644
--- a/engines/access/asurface.cpp
+++ b/engines/access/asurface.cpp
@@ -102,7 +102,7 @@ void ImageEntryList::addToList(ImageEntry &ie) {
int ASurface::_clipWidth;
int ASurface::_clipHeight;
-ASurface::ASurface() {
+ASurface::ASurface(): Graphics::Surface() {
_leftSkip = _rightSkip = 0;
_topSkip = _bottomSkip = 0;
_lastBoundsX = _lastBoundsY = 0;
@@ -110,6 +110,7 @@ ASurface::ASurface() {
_orgX1 = _orgY1 = 0;
_orgX2 = _orgY2 = 0;
_lColor = 0;
+ _maxChars = 0;
}
ASurface::~ASurface() {
@@ -186,7 +187,7 @@ void ASurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Poi
}
}
-void ASurface::transCopyFrom(ASurface *src, const Common::Point &destPos) {
+void ASurface::transBlitFrom(ASurface *src, const Common::Point &destPos) {
if (getPixels() == nullptr)
create(w, h);
@@ -201,7 +202,7 @@ void ASurface::transCopyFrom(ASurface *src, const Common::Point &destPos) {
}
}
-void ASurface::transCopyFrom(ASurface *src, const Common::Rect &bounds) {
+void ASurface::transBlitFrom(ASurface *src, const Common::Rect &bounds) {
const int SCALE_LIMIT = 0x100;
int scaleX = SCALE_LIMIT * bounds.width() / src->w;
int scaleY = SCALE_LIMIT * bounds.height() / src->h;
@@ -247,11 +248,12 @@ void ASurface::transCopyFrom(ASurface *src, const Common::Rect &bounds) {
}
}
-void ASurface::transCopyFrom(ASurface &src) {
- copyFrom(src);
+void ASurface::transBlitFrom(ASurface &src) {
+ blitFrom(src);
}
-void ASurface::copyFrom(Graphics::Surface &src) {
+void ASurface::blitFrom(Graphics::Surface &src) {
+ assert(w >= src.w && h >= src.h);
for (int y = 0; y < src.h; ++y) {
const byte *srcP = (const byte *)src.getBasePtr(0, y);
byte *destP = (byte *)getBasePtr(0, y);
@@ -260,7 +262,7 @@ void ASurface::copyFrom(Graphics::Surface &src) {
}
void ASurface::copyBuffer(Graphics::Surface *src) {
- copyFrom(*src);
+ blitFrom(*src);
}
void ASurface::plotF(SpriteFrame *frame, const Common::Point &pt) {
@@ -272,14 +274,14 @@ void ASurface::plotB(SpriteFrame *frame, const Common::Point &pt) {
}
void ASurface::sPlotF(SpriteFrame *frame, const Common::Rect &bounds) {
- transCopyFrom(frame, bounds);
+ transBlitFrom(frame, bounds);
}
void ASurface::sPlotB(SpriteFrame *frame, const Common::Rect &bounds) {
ASurface flippedFrame;
frame->flipHorizontal(flippedFrame);
- transCopyFrom(&flippedFrame, bounds);
+ transBlitFrom(&flippedFrame, bounds);
}
void ASurface::copyBlock(ASurface *src, const Common::Rect &bounds) {
diff --git a/engines/access/asurface.h b/engines/access/asurface.h
index 763e3e629e..4fb47b9c09 100644
--- a/engines/access/asurface.h
+++ b/engines/access/asurface.h
@@ -95,19 +95,19 @@ public:
virtual void drawRect();
- virtual void transCopyFrom(ASurface *src, const Common::Point &destPos);
+ virtual void transBlitFrom(ASurface *src, const Common::Point &destPos);
- virtual void transCopyFrom(ASurface *src, const Common::Rect &bounds);
+ virtual void transBlitFrom(ASurface *src, const Common::Rect &bounds);
- virtual void transCopyFrom(ASurface &src);
+ virtual void transBlitFrom(ASurface &src);
- virtual void copyFrom(Graphics::Surface &src);
+ virtual void blitFrom(Graphics::Surface &src);
virtual void copyBuffer(Graphics::Surface *src);
virtual void addDirtyRect(const Common::Rect &r) {}
- void copyTo(ASurface *dest) { dest->copyFrom(*this); }
+ void copyTo(ASurface *dest) { dest->blitFrom(*this); }
void saveBlock(const Common::Rect &bounds);
diff --git a/engines/access/bubble_box.cpp b/engines/access/bubble_box.cpp
index e37a8142e8..28c211991c 100644
--- a/engines/access/bubble_box.cpp
+++ b/engines/access/bubble_box.cpp
@@ -27,13 +27,12 @@
namespace Access {
BubbleBox::BubbleBox(AccessEngine *vm) : Manager(vm) {
+ _startItem = 0;
+ _startBox = 0;
+ _charCol = _rowOff = 0;
_type = TYPE_2;
_bounds = Common::Rect(64, 32, 64 + 130, 32 + 122);
_bubbleDisplStr = "";
- _fieldD = 0;
- _fieldE = 0;
- _fieldF = 0;
- _field10 = 0;
}
void BubbleBox::load(Common::SeekableReadStream *stream) {
diff --git a/engines/access/bubble_box.h b/engines/access/bubble_box.h
index 0130344c7e..0b3f139520 100644
--- a/engines/access/bubble_box.h
+++ b/engines/access/bubble_box.h
@@ -49,10 +49,6 @@ public:
Common::StringArray _nameIndex;
Common::String _bubbleTitle;
Common::String _bubbleDisplStr;
- int _fieldD;
- int _fieldE;
- int _fieldF;
- int _field10;
Common::Array<Common::Rect> _bubbles;
public:
diff --git a/engines/access/char.cpp b/engines/access/char.cpp
index 5bc6707509..b359bcf13a 100644
--- a/engines/access/char.cpp
+++ b/engines/access/char.cpp
@@ -108,8 +108,8 @@ void CharManager::loadChar(int charId) {
_vm->_screen->fadeIn();
}
- _vm->_buffer1.copyFrom(*_vm->_screen);
- _vm->_buffer2.copyFrom(*_vm->_screen);
+ _vm->_buffer1.blitFrom(*_vm->_screen);
+ _vm->_buffer2.blitFrom(*_vm->_screen);
_vm->_screen->setDisplayScan();
if (_charFlag != 2 && _charFlag != 3) {
diff --git a/engines/access/char.h b/engines/access/char.h
index e89cdae49f..6fb4934978 100644
--- a/engines/access/char.h
+++ b/engines/access/char.h
@@ -51,11 +51,8 @@ private:
void charMenu();
public:
Common::Array<CharEntry> _charTable;
- int _converseMode;
int _charFlag;
- // Fields that are included in savegames
- int _conversation;
public:
CharManager(AccessEngine *vm);
diff --git a/engines/access/decompress.cpp b/engines/access/decompress.cpp
index 62bff87860..c5656afa51 100644
--- a/engines/access/decompress.cpp
+++ b/engines/access/decompress.cpp
@@ -32,8 +32,9 @@ void LzwDecompressor::decompress(byte *source, byte *dest) {
_source = source;
- byte litByte;
- uint16 copyLength, maxCodeValue, code, nextCode, lastCode, oldCode;
+ byte litByte = 0;
+ uint16 oldCode = 0;
+ uint16 copyLength, maxCodeValue, code, nextCode, lastCode;
byte *copyBuf = new byte[8192];
diff --git a/engines/access/events.cpp b/engines/access/events.cpp
index 0867b09765..6ffe67acfb 100644
--- a/engines/access/events.cpp
+++ b/engines/access/events.cpp
@@ -140,6 +140,8 @@ void EventsManager::pollEvents(bool skipTimers) {
if (checkForNextTimerUpdate() && !skipTimers)
nextTimer();
+ _vm->_sound->checkSoundQueue();
+
_wheelUp = _wheelDown = false;
Common::Event event;
diff --git a/engines/access/font.cpp b/engines/access/font.cpp
index da8f0b6ec5..8af183f193 100644
--- a/engines/access/font.cpp
+++ b/engines/access/font.cpp
@@ -27,6 +27,8 @@ namespace Access {
byte Font::_fontColors[4];
Font::Font() {
+ _bitWidth = 0;
+ _height = 0;
}
Font::~Font() {
diff --git a/engines/access/inventory.cpp b/engines/access/inventory.cpp
index 8db62a45fc..df499ba705 100644
--- a/engines/access/inventory.cpp
+++ b/engines/access/inventory.cpp
@@ -57,6 +57,7 @@ InventoryManager::InventoryManager(AccessEngine *vm) : Manager(vm) {
_startAboutItem = 0;
_startTravelItem = 0;
_iconDisplayFlag = true;
+ _boxNum = 0;
const char *const *names;
const int *combineP;
diff --git a/engines/access/martian/martian_game.cpp b/engines/access/martian/martian_game.cpp
index 6392206209..4e4a5135a6 100644
--- a/engines/access/martian/martian_game.cpp
+++ b/engines/access/martian/martian_game.cpp
@@ -100,8 +100,8 @@ void MartianEngine::doTitle() {
_files->_setPaletteFlag = false;
_files->loadScreen(0, 3);
- _buffer2.copyFrom(*_screen);
- _buffer1.copyFrom(*_screen);
+ _buffer2.blitFrom(*_screen);
+ _buffer1.blitFrom(*_screen);
_screen->forceFadeIn();
_sound->playSound(1);
@@ -115,13 +115,13 @@ void MartianEngine::doTitle() {
_files->loadScreen(0, 4);
_sound->playSound(1);
- _buffer2.copyFrom(*_screen);
- _buffer1.copyFrom(*_screen);
+ _buffer2.blitFrom(*_screen);
+ _buffer1.blitFrom(*_screen);
_sound->playSound(1);
const int COUNTDOWN[6] = { 2, 0x80, 1, 0x7d, 0, 0x87 };
for (_pCount = 0; _pCount < 3; ++_pCount) {
- _buffer2.copyFrom(_buffer1);
+ _buffer2.blitFrom(_buffer1);
int id = READ_LE_UINT16(COUNTDOWN + _pCount * 4);
int xp = READ_LE_UINT16(COUNTDOWN + _pCount * 4 + 2);
_screen->plotImage(_objectsTable[0], id, Common::Point(xp, 71));
diff --git a/engines/access/player.cpp b/engines/access/player.cpp
index d547aedc1d..e47daf532c 100644
--- a/engines/access/player.cpp
+++ b/engines/access/player.cpp
@@ -48,7 +48,6 @@ Player::Player(AccessEngine *vm) : Manager(vm), ImageEntry() {
_playerSprites1 = nullptr;
_manPal1 = nullptr;
_frameNumber = 0;
- _monData = nullptr;
_rawTempL = 0;
_rawXTemp = 0;
_rawYTempL = 0;
@@ -73,6 +72,12 @@ Player::Player(AccessEngine *vm) : Manager(vm), ImageEntry() {
_playerDirection = NONE;
_xFlag = _yFlag = 0;
_inactiveYOff = 0;
+
+ _sideWalkMin = _sideWalkMax = 0;
+ _upWalkMin = _upWalkMax = 0;
+ _downWalkMin = _downWalkMax = 0;
+ _diagUpWalkMin = _diagUpWalkMax = 0;
+ _diagDownWalkMin = _diagDownWalkMax = 0;
}
Player::~Player() {
diff --git a/engines/access/player.h b/engines/access/player.h
index 26caec681f..329cc15ed2 100644
--- a/engines/access/player.h
+++ b/engines/access/player.h
@@ -84,7 +84,6 @@ public:
Direction _playerDirection;
SpriteResource *_playerSprites;
// Fields in original Player structure
- byte *_monData;
int _walkOffRight[PLAYER_DATA_COUNT];
int _walkOffLeft[PLAYER_DATA_COUNT];
int _walkOffUp[PLAYER_DATA_COUNT];
diff --git a/engines/access/room.cpp b/engines/access/room.cpp
index f7c2eabd0f..607259ec6f 100644
--- a/engines/access/room.cpp
+++ b/engines/access/room.cpp
@@ -370,9 +370,9 @@ void Room::loadPlayField(int fileNum, int subfile) {
screen.loadRawPalette(playData->_stream);
// Copy off the tile data
- _tileSize = (int)header[2] << 8;
- _tile = new byte[_tileSize];
- playData->_stream->read(_tile, _tileSize);
+ int tileSize = (int)header[2] << 8;
+ _tile = new byte[tileSize];
+ playData->_stream->read(_tile, tileSize);
// Copy off the playfield data
_matrixSize = header[0] * header[1];
diff --git a/engines/access/room.h b/engines/access/room.h
index 44279fa6b1..eec273e3f4 100644
--- a/engines/access/room.h
+++ b/engines/access/room.h
@@ -124,7 +124,6 @@ public:
int _playFieldWidth;
int _playFieldHeight;
byte *_tile;
- int _tileSize;
int _selectCommand;
bool _conFlag;
public:
diff --git a/engines/access/screen.cpp b/engines/access/screen.cpp
index 35069ba683..970a8f3079 100644
--- a/engines/access/screen.cpp
+++ b/engines/access/screen.cpp
@@ -56,6 +56,7 @@ Screen::Screen(AccessEngine *vm) : _vm(vm) {
_bufferBytesWide = _vWindowBytesWide = this->w;
_vWindowLinesTall = this->h;
+ _vWindowWidth = _vWindowHeight = 0;
_clipWidth = _vWindowBytesWide - 1;
_clipHeight = _vWindowLinesTall - 1;
_startCycle = 0;
@@ -266,19 +267,19 @@ void Screen::drawRect() {
ASurface::drawRect();
}
-void Screen::transCopyFrom(ASurface *src, const Common::Point &destPos) {
+void Screen::transBlitFrom(ASurface *src, const Common::Point &destPos) {
addDirtyRect(Common::Rect(destPos.x, destPos.y, destPos.x + src->w, destPos.y + src->h));
- ASurface::transCopyFrom(src, destPos);
+ ASurface::transBlitFrom(src, destPos);
}
-void Screen::transCopyFrom(ASurface *src, const Common::Rect &bounds) {
+void Screen::transBlitFrom(ASurface *src, const Common::Rect &bounds) {
addDirtyRect(bounds);
- ASurface::transCopyFrom(src, bounds);
+ ASurface::transBlitFrom(src, bounds);
}
-void Screen::copyFrom(Graphics::Surface &src) {
+void Screen::blitFrom(Graphics::Surface &src) {
addDirtyRect(Common::Rect(0, 0, src.w, src.h));
- ASurface::copyFrom(src);
+ ASurface::blitFrom(src);
}
void Screen::copyBuffer(Graphics::Surface *src) {
diff --git a/engines/access/screen.h b/engines/access/screen.h
index 0fa111c21c..d45a533f9a 100644
--- a/engines/access/screen.h
+++ b/engines/access/screen.h
@@ -92,11 +92,11 @@ public:
virtual void drawRect();
- virtual void transCopyFrom(ASurface *src, const Common::Point &destPos);
+ virtual void transBlitFrom(ASurface *src, const Common::Point &destPos);
- virtual void transCopyFrom(ASurface *src, const Common::Rect &bounds);
+ virtual void transBlitFrom(ASurface *src, const Common::Rect &bounds);
- virtual void copyFrom(Graphics::Surface &src);
+ virtual void blitFrom(Graphics::Surface &src);
virtual void copyBuffer(Graphics::Surface *src);
diff --git a/engines/access/scripts.cpp b/engines/access/scripts.cpp
index 2e22d9a2ce..1bd24894d7 100644
--- a/engines/access/scripts.cpp
+++ b/engines/access/scripts.cpp
@@ -29,10 +29,12 @@ namespace Access {
Scripts::Scripts(AccessEngine *vm) : Manager(vm) {
_resource = nullptr;
+ _specialFunction = -1;
_data = nullptr;
_sequence = 0;
_endFlag = false;
_returnCode = 0;
+ _scriptCommand = 0;
_choice = 0;
_choiceStart = 0;
_charsOrg = Common::Point(0, 0);
@@ -73,7 +75,7 @@ void Scripts::charLoop() {
_sequence = 2000;
searchForSequence();
_vm->_images.clear();
- _vm->_buffer2.copyFrom(_vm->_buffer1);
+ _vm->_buffer2.blitFrom(_vm->_buffer1);
_vm->_newRects.clear();
executeScript();
@@ -792,7 +794,7 @@ void Scripts::cmdFreeSound() {
charLoop();
_vm->_events->pollEvents();
- } while (!_vm->shouldQuit() && sound._playingSound);
+ } while (!_vm->shouldQuit() && sound.isSFXPlaying());
// Free the sounds
while (sound._soundTable.size() > 0) {
diff --git a/engines/access/sound.cpp b/engines/access/sound.cpp
index a7d96dac9a..da267bdc4c 100644
--- a/engines/access/sound.cpp
+++ b/engines/access/sound.cpp
@@ -22,7 +22,6 @@
#include "common/algorithm.h"
#include "audio/mixer.h"
-#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/wave.h"
#include "access/access.h"
@@ -31,8 +30,6 @@
namespace Access {
SoundManager::SoundManager(AccessEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
- _playingSound = false;
- _isVoice = false;
}
SoundManager::~SoundManager() {
@@ -44,11 +41,23 @@ void SoundManager::clearSounds() {
for (uint i = 0; i < _soundTable.size(); ++i)
delete _soundTable[i]._res;
+
_soundTable.clear();
+
+ if (_mixer->isSoundHandleActive(_effectsHandle))
+ _mixer->stopHandle(_effectsHandle);
+
+ if (_queue.size())
+ _queue.remove_at(0);
+
+ while (_queue.size()) {
+ delete _queue[0];
+ _queue.remove_at(0);
+ }
}
-void SoundManager::queueSound(int idx, int fileNum, int subfile) {
- debugC(1, kDebugSound, "queueSound(%d, %d, %d)", idx, fileNum, subfile);
+void SoundManager::loadSoundTable(int idx, int fileNum, int subfile, int priority) {
+ debugC(1, kDebugSound, "loadSoundTable(%d, %d, %d)", idx, fileNum, subfile);
Resource *soundResource;
@@ -58,7 +67,7 @@ void SoundManager::queueSound(int idx, int fileNum, int subfile) {
delete _soundTable[idx]._res;
soundResource = _vm->_files->loadFile(fileNum, subfile);
_soundTable[idx]._res = soundResource;
- _soundTable[idx]._priority = 1;
+ _soundTable[idx]._priority = priority;
}
Resource *SoundManager::loadSound(int fileNum, int subfile) {
@@ -77,19 +86,14 @@ void SoundManager::playSound(Resource *res, int priority) {
debugC(1, kDebugSound, "playSound");
byte *resourceData = res->data();
- Audio::SoundHandle audioHandle;
- Audio::RewindableAudioStream *audioStream = 0;
assert(res->_size >= 32);
- // HACK: Simulates queueing for the rare sounds played one after the other
- while (_mixer->hasActiveChannelOfType(Audio::Mixer::kSFXSoundType))
- ;
-
if (READ_BE_UINT32(resourceData) == MKTAG('R','I','F','F')) {
// CD version uses WAVE-files
Common::SeekableReadStream *waveStream = new Common::MemoryReadStream(resourceData, res->_size, DisposeAfterUse::NO);
- audioStream = Audio::makeWAVStream(waveStream, DisposeAfterUse::YES);
+ Audio::RewindableAudioStream *audioStream = Audio::makeWAVStream(waveStream, DisposeAfterUse::YES);
+ _queue.push_back(audioStream);
} else if (READ_BE_UINT32(resourceData) == MKTAG('S', 'T', 'E', 'V')) {
// sound files have a fixed header of 32 bytes in total
@@ -130,22 +134,34 @@ void SoundManager::playSound(Resource *res, int priority) {
return;
}
- audioStream = Audio::makeRawStream(resourceData + 32, sampleSize, sampleRate, 0);
+ Audio::RewindableAudioStream *audioStream = Audio::makeRawStream(resourceData + 32, sampleSize, sampleRate, 0, DisposeAfterUse::NO);
+ _queue.push_back(audioStream);
} else
error("Unknown format");
- audioHandle = Audio::SoundHandle();
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &audioHandle,
- audioStream, -1, _mixer->kMaxChannelVolume, 0,
- DisposeAfterUse::NO);
-
- /*
- Audio::QueuingAudioStream *audioStream = Audio::makeQueuingAudioStream(22050, false);
- audioStream->queueBuffer(data, size, DisposeAfterUse::YES, 0);
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, audioStream, -1,
- Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::YES, false);
- */
+ if (!_mixer->isSoundHandleActive(_effectsHandle))
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_effectsHandle,
+ _queue[0], -1, _mixer->kMaxChannelVolume, 0,
+ DisposeAfterUse::YES);
+}
+
+void SoundManager::checkSoundQueue() {
+ debugC(5, kDebugSound, "checkSoundQueue");
+
+ if (_queue.empty() || _mixer->isSoundHandleActive(_effectsHandle))
+ return;
+
+ _queue.remove_at(0);
+
+ if (_queue.size())
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_effectsHandle,
+ _queue[0], -1, _mixer->kMaxChannelVolume, 0,
+ DisposeAfterUse::YES);
+}
+
+bool SoundManager::isSFXPlaying() {
+ return _mixer->isSoundHandleActive(_effectsHandle);
}
void SoundManager::loadSounds(Common::Array<RoomInfo::SoundIdent> &sounds) {
diff --git a/engines/access/sound.h b/engines/access/sound.h
index d0f4584fac..90f6656e26 100644
--- a/engines/access/sound.h
+++ b/engines/access/sound.h
@@ -24,6 +24,7 @@
#define ACCESS_SOUND_H
#include "common/scummsys.h"
+#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "access/files.h"
#include "audio/midiplayer.h"
@@ -47,22 +48,23 @@ class SoundManager {
private:
AccessEngine *_vm;
Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
+ Audio::SoundHandle _effectsHandle;
+ Common::Array<Audio::RewindableAudioStream *> _queue;
void clearSounds();
void playSound(Resource *res, int priority);
public:
Common::Array<SoundEntry> _soundTable;
- bool _playingSound;
- bool _isVoice;
public:
SoundManager(AccessEngine *vm, Audio::Mixer *mixer);
~SoundManager();
- void queueSound(int idx, int fileNum, int subfile);
+ void loadSoundTable(int idx, int fileNum, int subfile, int priority = 1);
void playSound(int soundIndex);
+ void checkSoundQueue();
+ bool isSFXPlaying();
Resource *loadSound(int fileNum, int subfile);
void loadSounds(Common::Array<RoomInfo::SoundIdent> &sounds);
diff --git a/engines/access/video.cpp b/engines/access/video.cpp
index b7d5652e5b..63d0aa5c89 100644
--- a/engines/access/video.cpp
+++ b/engines/access/video.cpp
@@ -27,10 +27,21 @@ namespace Access {
VideoPlayer::VideoPlayer(AccessEngine *vm) : Manager(vm) {
_vidSurface = nullptr;
+ _videoData = nullptr;
+ _startCoord = nullptr;
+
+ _frameCount = 0;
+ _xCount = 0;
+ _scanCount = 0;
+ _frameSize = 0;
_videoFrame = 0;
_soundFlag = false;
_soundFrame = 0;
- _videoData = nullptr;
+ _videoEnd = false;
+
+ _header._frameCount = 0;
+ _header._width = _header._height = 0;
+ _header._flags = VIDEOFLAG_NONE;
}
VideoPlayer::~VideoPlayer() {
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index e7285d8112..3230b4e5d3 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -276,15 +276,13 @@ SaveStateList AgiMetaEngine::listSaves(const char *target) const {
int AgiMetaEngine::getMaximumSaveSlot() const { return 999; }
void AgiMetaEngine::removeSaveState(const char *target, int slot) const {
- char fileName[MAXPATHLEN];
- sprintf(fileName, "%s.%03d", target, slot);
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
g_system->getSavefileManager()->removeSavefile(fileName);
}
SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
const uint32 AGIflag = MKTAG('A','G','I',':');
- char fileName[MAXPATHLEN];
- sprintf(fileName, "%s.%03d", target, slot);
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
diff --git a/engines/agi/loader_v2.cpp b/engines/agi/loader_v2.cpp
index 787eeaa0c7..693c53c2bf 100644
--- a/engines/agi/loader_v2.cpp
+++ b/engines/agi/loader_v2.cpp
@@ -135,13 +135,13 @@ int AgiLoader_v2::unloadResource(int t, int n) {
*/
uint8 *AgiLoader_v2::loadVolRes(struct AgiDir *agid) {
uint8 *data = NULL;
- char x[MAXPATHLEN], *path;
+ char x[6];
Common::File fp;
unsigned int sig;
+ Common::String path;
- sprintf(x, "vol.%i", agid->volume);
- path = x;
- debugC(3, kDebugLevelResources, "Vol res: path = %s", path);
+ path = Common::String::format("vol.%i", agid->volume);
+ debugC(3, kDebugLevelResources, "Vol res: path = %s", path.c_str());
if (agid->offset != _EMPTY && fp.open(path)) {
debugC(3, kDebugLevelResources, "loading resource at offset %d", agid->offset);
diff --git a/engines/agi/loader_v3.cpp b/engines/agi/loader_v3.cpp
index fa135e5476..39759b4649 100644
--- a/engines/agi/loader_v3.cpp
+++ b/engines/agi/loader_v3.cpp
@@ -198,14 +198,13 @@ int AgiLoader_v3::unloadResource(int t, int n) {
* NULL is returned if unsucsessful.
*/
uint8 *AgiLoader_v3::loadVolRes(AgiDir *agid) {
- char x[MAXPATHLEN];
+ char x[8];
uint8 *data = NULL, *compBuffer;
Common::File fp;
Common::String path;
debugC(3, kDebugLevelResources, "(%p)", (void *)agid);
- sprintf(x, "vol.%i", agid->volume);
- path = Common::String(_vm->_game.name) + x;
+ path = Common::String::format("%svol.%i", _vm->_game.name, agid->volume);
if (agid->offset != _EMPTY && fp.open(path)) {
fp.seek(agid->offset, SEEK_SET);
diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp
index 6e1b93d0b8..4acdea3fde 100644
--- a/engines/cge2/detection.cpp
+++ b/engines/cge2/detection.cpp
@@ -80,6 +80,16 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
+
+ {
+ "sfinx", "Freeware v1.1",
+ {
+ {"vol.cat", 0, "f158e469dccbebc5a632eb848df89779", 129024},
+ {"vol.dat", 0, "d40a6b4ae173d6930be54ba56bee15d5", 34182773},
+ AD_LISTEND
+ },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ },
AD_TABLE_END_MARKER
};
diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp
index 833363669d..a84bd11cb1 100644
--- a/engines/drascula/detection.cpp
+++ b/engines/drascula/detection.cpp
@@ -382,8 +382,7 @@ SaveStateList DrasculaMetaEngine::listSaves(const char *target) const {
}
SaveStateDescriptor DrasculaMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
- char fileName[MAXPATHLEN];
- sprintf(fileName, "%s.%03d", target, slot);
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
diff --git a/engines/fullpipe/inventory.cpp b/engines/fullpipe/inventory.cpp
index e79f9c54df..f9b507c50b 100644
--- a/engines/fullpipe/inventory.cpp
+++ b/engines/fullpipe/inventory.cpp
@@ -126,7 +126,7 @@ void Inventory2::removeItem2(Scene *sceneObj, int itemId, int x, int y, int prio
int idx = getInventoryItemIndexById(itemId);
if (idx >= 0) {
- if (_inventoryItems[idx]->itemId >> 16) {
+ if (_inventoryItems[idx]->count) {
removeItem(itemId, 1);
Scene *sc = g_fp->accessScene(_sceneId);
diff --git a/engines/fullpipe/mgm.cpp b/engines/fullpipe/mgm.cpp
index aacfd5452a..1c8ca2a7b1 100644
--- a/engines/fullpipe/mgm.cpp
+++ b/engines/fullpipe/mgm.cpp
@@ -155,13 +155,14 @@ void MGM::rebuildTables(int objId) {
if (!obj)
return;
- for (uint i = 0; i < obj->_staticsList.size(); i++)
+ for (uint i = 0; i < obj->_staticsList.size(); i++) {
_items[idx]->statics.push_back((Statics *)obj->_staticsList[i]);
+ _items[idx]->subItems.push_back(new MGMSubItem);
+ }
+
for (uint i = 0; i < obj->_movements.size(); i++)
_items[idx]->movements1.push_back((Movement *)obj->_movements[i]);
-
- _items[idx]->subItems.clear();
}
int MGM::getItemIndexById(int objId) {
diff --git a/engines/fullpipe/scenes/scene04.cpp b/engines/fullpipe/scenes/scene04.cpp
index fd1ececdf2..4a87ae5b87 100644
--- a/engines/fullpipe/scenes/scene04.cpp
+++ b/engines/fullpipe/scenes/scene04.cpp
@@ -949,7 +949,7 @@ void sceneHandler04_springWobble() {
if (g_vars->scene04_bottleWeight < newdelta)
g_vars->scene04_springOffset--;
- if ((oldDynIndex > g_vars->scene04_bottleWeight && newdelta > g_vars->scene04_bottleWeight) || newdelta <= g_vars->scene04_bottleWeight) {
+ if ((oldDynIndex <= g_vars->scene04_bottleWeight && newdelta > g_vars->scene04_bottleWeight) || newdelta <= g_vars->scene04_bottleWeight) {
g_vars->scene04_springDelay++;
if (g_vars->scene04_springOffset && g_vars->scene04_springDelay > 1) {
@@ -960,6 +960,8 @@ void sceneHandler04_springWobble() {
Common::Point point;
+ int oldpos = g_vars->scene04_spring->getCurrDimensions(point)->y - oldDynIndex;
+
if (g_vars->scene04_dynamicPhaseIndex) {
if (!g_vars->scene04_spring->_movement)
g_vars->scene04_spring->startAnim(MV_SPR_LOWER, 0, -1);
@@ -969,8 +971,9 @@ void sceneHandler04_springWobble() {
g_vars->scene04_spring->changeStatics2(ST_SPR_UP);
}
- if (g_vars->scene04_dynamicPhaseIndex != oldDynIndex)
- sceneHandler04_bottleUpdateObjects(oldDynIndex - g_vars->scene04_dynamicPhaseIndex);
+ if (g_vars->scene04_dynamicPhaseIndex != oldDynIndex) {
+ sceneHandler04_bottleUpdateObjects(oldpos - (g_vars->scene04_spring->getCurrDimensions(point)->y - g_vars->scene04_dynamicPhaseIndex));
+ }
}
void sceneHandler04_leaveScene() {
diff --git a/engines/fullpipe/scenes/scene16.cpp b/engines/fullpipe/scenes/scene16.cpp
index e9d3a37efd..df005950d2 100644
--- a/engines/fullpipe/scenes/scene16.cpp
+++ b/engines/fullpipe/scenes/scene16.cpp
@@ -182,7 +182,7 @@ void sceneHandler16_fillMug() {
mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC16_BOYOUT), 0, 1);
mq->replaceKeyCode(-1, g_vars->scene16_walkingBoy->_okeyCode);
- if (!mq || mq->chain(g_vars->scene16_walkingBoy))
+ if (mq->chain(g_vars->scene16_walkingBoy))
return;
} else {
if (!g_vars->scene16_walkingGirl)
diff --git a/engines/fullpipe/statics.cpp b/engines/fullpipe/statics.cpp
index 880c2eb0df..de3e1ea728 100644
--- a/engines/fullpipe/statics.cpp
+++ b/engines/fullpipe/statics.cpp
@@ -1048,8 +1048,11 @@ MessageQueue *StaticANIObject::changeStatics1(int msgNum) {
if (_flags & 1)
_messageQueueId = mq->_id;
} else {
- if (!queueMessageQueue(mq))
+ if (!queueMessageQueue(mq)) {
+ delete mq;
+
return 0;
+ }
g_fp->_globalMessageQueueList->addMessageQueue(mq);
}
@@ -1594,6 +1597,12 @@ Movement::Movement(Movement *src, int *oldIdxs, int newSize, StaticANIObject *an
newSize = src->_dynamicPhases.size();
}
+ if (!newSize) {
+ warning("Movement::Movement: newSize = 0");
+
+ return;
+ }
+
_framePosOffsets = (Common::Point **)calloc(newSize, sizeof(Common::Point *));
for (int i = 0; i < newSize; i++)
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index d6bdef946b..32d1a58765 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -2069,6 +2069,20 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::DE_DEU, Common::kPlatformDOS, ADGF_ADDENGLISH, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Larry 3 - German DOS (German+English, 5 1/4" floppies)
+ // SCI interpreter version S.old.114 (executable), VERSION is "1.056"
+ {"lsl3", "", {
+ {"resource.map", 0, "2468da5d664bb6ca3df866074a05e43c", 8910},
+ {"resource.001", 0, "3827a9b17b926e12dcc336860f50612a", 163326},
+ {"resource.002", 0, "3827a9b17b926e12dcc336860f50612a", 312436},
+ {"resource.003", 0, "3827a9b17b926e12dcc336860f50612a", 347307},
+ {"resource.004", 0, "3827a9b17b926e12dcc336860f50612a", 332369},
+ {"resource.005", 0, "3827a9b17b926e12dcc336860f50612a", 347654},
+ {"resource.006", 0, "3827a9b17b926e12dcc336860f50612a", 326011},
+ {"resource.007", 0, "3827a9b17b926e12dcc336860f50612a", 309553},
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_ADDENGLISH, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Larry 3 - French DOS (provided by richiefs in bug report #2670691, also includes english language)
// Executable scanning reports "S.old.123"
// SCI interpreter version 0.000.572 (just a guess)
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index c07dc925e0..527c8f0ae0 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -205,7 +205,7 @@ static kLanguage charToLanguage(const char c) {
Common::String SciEngine::getSciLanguageString(const Common::String &str, kLanguage requestedLanguage, kLanguage *secondaryLanguage, uint16 *languageSplitter) const {
kLanguage foundLanguage = K_LANG_NONE;
- const byte *textPtr = (byte *)str.c_str();
+ const byte *textPtr = (const byte *)str.c_str();
byte curChar = 0;
byte curChar2 = 0;
diff --git a/engines/sci/graphics/portrait.cpp b/engines/sci/graphics/portrait.cpp
index 668de616fb..3311f47022 100644
--- a/engines/sci/graphics/portrait.cpp
+++ b/engines/sci/graphics/portrait.cpp
@@ -57,13 +57,39 @@ void Portrait::init() {
// 4 bytes paletteSize (base 1)
// -> 17 bytes
// paletteSize bytes paletteData
- // 14 bytes bitmap header
- // -> 4 bytes unknown
- // -> 2 bytes height
- // -> 2 bytes width
- // -> 6 bytes unknown
- // height * width bitmap data
- // another animation count times bitmap header and data
+ //
+ // bitmap-data follows, total of [animation count]
+ // 14 bytes bitmap header
+ // -> 4 bytes unknown
+ // -> 2 bytes height
+ // -> 2 bytes width
+ // -> 6 bytes unknown
+ // height * width bitmap data
+ //
+ // 4 bytes offset table size (may be larger than the actual known entries?!)
+ // 14 bytes all zeroes (dummy entry?!)
+ //
+ // 14 bytes for each entry
+ // -> 2 bytes displace X
+ // -> 2 bytes displace Y
+ // -> 2 bytes height (again)
+ // -> 2 bytes width (again)
+ // -> 6 bytes unknown (normally 01 00 00 00 00 00 for delta bitmaps, 00 00 00 00 00 00 for first bitmap)
+ // random data may be used as filler
+ //
+ // 4 bytes lip sync id table size (is [lip sync id count] * 4, should be 0x2E0 for all actors)
+ // 4 bytes per lip sync id
+ // -> 1 byte length of ID
+ // -> 3 bytes actual ID
+ //
+ // 4 bytes lip sync id data table size (seems to be the same for all actors, always 0x220 in size)
+ // 1 byte animation number or 0xFF as terminator
+ // 1 byte delay, if last byte was not terminator
+ // one array for every lip sync id
+ //
+ // 4 bytes appended, seem to be random
+ // 9E11120E for alex
+ // 9E9E9E9E for vizier
int32 fileSize = 0;
Common::SeekableReadStream *file =
SearchMan.createReadStreamForMember("actors/" + _resourceName + ".bin");
@@ -202,8 +228,9 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
if (raveResource->size < 4000) {
memcpy(debugPrint, raveResource->data, raveResource->size);
debugPrint[raveResource->size] = 0; // set terminating NUL
+ debug("kPortrait: using actor %s", _resourceName.c_str());
debug("kPortrait (noun %d, verb %d, cond %d, seq %d)", noun, verb, cond, seq);
- debug("kPortrait: %s", debugPrint);
+ debug("kPortrait: rave data is '%s'", debugPrint);
}
#endif
@@ -273,6 +300,14 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
raveLipSyncData = NULL;
}
+#ifdef DEBUG_PORTRAIT
+ if (raveID & 0x0ff) {
+ debug("kPortrait: rave '%c%c' after %d ticks", raveID >> 8, raveID & 0x0ff, raveTicks);
+ } else if (raveID) {
+ debug("kPortrait: rave '%c' after %d ticks", raveID >> 8, raveTicks);
+ }
+#endif
+
timerPosition += raveTicks;
// Wait till syncTime passed, then show specific animation bitmap
@@ -295,6 +330,8 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
timerPositionWithin = timerPosition;
raveLipSyncTicks = *raveLipSyncData++;
while ( (raveLipSyncData < _lipSyncDataOffsetTableEnd) && (raveLipSyncTicks != 0xFF) ) {
+ if (raveLipSyncTicks)
+ raveLipSyncTicks--; // 1 -> wait 0 ticks, 2 -> wait 1 tick, etc.
timerPositionWithin += raveLipSyncTicks;
do {
@@ -308,6 +345,13 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
} while ((curPosition != -1) && (curPosition < timerPositionWithin) && (!userAbort));
raveLipSyncBitmapNr = *raveLipSyncData++;
+#ifdef DEBUG_PORTRAIT
+ if (!raveLipSyncTicks) {
+ debug("kPortrait: showing frame %d", raveLipSyncBitmapNr);
+ } else {
+ debug("kPortrait: showing frame %d after %d ticks", raveLipSyncBitmapNr, raveLipSyncTicks);
+ }
+#endif
// bitmap nr within sync data is base 1, we need base 0
raveLipSyncBitmapNr--;
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 8b0e76332f..2f95bf7751 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -238,6 +238,8 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
_vectorPutPixelPtr = &GfxScreen::putPixelDisplayUpscaled;
_putPixelPtr = &GfxScreen::putPixelDisplayUpscaled;
break;
+ case GFX_SCREEN_UPSCALED_DISABLED:
+ break;
}
}
diff --git a/engines/zvision/core/console.cpp b/engines/zvision/core/console.cpp
index 4dd10d6f40..b5e542d777 100644
--- a/engines/zvision/core/console.cpp
+++ b/engines/zvision/core/console.cpp
@@ -52,6 +52,7 @@ Console::Console(ZVision *engine) : GUI::Debugger(), _engine(engine) {
registerCmd("setpanoramascale", WRAP_METHOD(Console, cmdSetPanoramaScale));
registerCmd("location", WRAP_METHOD(Console, cmdLocation));
registerCmd("dumpfile", WRAP_METHOD(Console, cmdDumpFile));
+ registerCmd("dumpfiles", WRAP_METHOD(Console, cmdDumpFiles));
}
bool Console::cmdLoadVideo(int argc, const char **argv) {
@@ -78,12 +79,14 @@ bool Console::cmdLoadSound(int argc, const char **argv) {
Audio::AudioStream *soundStream = makeRawZorkStream(argv[1], _engine);
Audio::SoundHandle handle;
_engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, soundStream, -1, 100, 0, DisposeAfterUse::YES, false, false);
-
} else if (argc == 4) {
int isStereo = atoi(argv[3]);
Common::File *file = new Common::File();
- file->open(argv[1]);
+ if (!_engine->getSearchManager()->openFile(*file, argv[1])) {
+ warning("File not found: %s", argv[1]);
+ return true;
+ }
Audio::AudioStream *soundStream = makeRawZorkStream(file, atoi(argv[2]), isStereo == 0 ? false : true);
Audio::SoundHandle handle;
@@ -103,8 +106,10 @@ bool Console::cmdRawToWav(int argc, const char **argv) {
}
Common::File file;
- if (!file.open(argv[1]))
+ if (!_engine->getSearchManager()->openFile(file, argv[1])) {
+ warning("File not found: %s", argv[1]);
return true;
+ }
Audio::AudioStream *audioStream = makeRawZorkStream(argv[1], _engine);
@@ -133,6 +138,10 @@ bool Console::cmdRawToWav(int argc, const char **argv) {
output.writeUint32LE(file.size() * 2);
int16 *buffer = new int16[file.size()];
audioStream->readBuffer(buffer, file.size());
+#ifndef SCUMM_LITTLE_ENDIAN
+ for (int i = 0; i < file.size(); ++i)
+ buffer[i] = TO_LE_16(buffer[i]);
+#endif
output.write(buffer, file.size() * 2);
delete[] buffer;
@@ -205,6 +214,20 @@ bool Console::cmdLocation(int argc, const char **argv) {
return true;
}
+void dumpFile(Common::SeekableReadStream *s, const char *outName) {
+ byte *buffer = new byte[s->size()];
+ s->read(buffer, s->size());
+
+ Common::DumpFile dumpFile;
+ dumpFile.open(outName);
+
+ dumpFile.write(buffer, s->size());
+ dumpFile.flush();
+ dumpFile.close();
+
+ delete[] buffer;
+}
+
bool Console::cmdDumpFile(int argc, const char **argv) {
if (argc != 2) {
debugPrintf("Use %s <fileName> to dump a file\n", argv[0]);
@@ -217,17 +240,31 @@ bool Console::cmdDumpFile(int argc, const char **argv) {
return true;
}
- byte *buffer = new byte[f.size()];
- f.read(buffer, f.size());
+ dumpFile(&f, argv[1]);
- Common::DumpFile dumpFile;
- dumpFile.open(argv[1]);
+ return true;
+}
- dumpFile.write(buffer, f.size());
- dumpFile.flush();
- dumpFile.close();
+bool Console::cmdDumpFiles(int argc, const char **argv) {
+ Common::String fileName;
+ Common::SeekableReadStream *in;
- delete[] buffer;
+ if (argc != 2) {
+ debugPrintf("Use %s <file extension> to dump all files with a specific extension\n", argv[0]);
+ return true;
+ }
+
+ SearchManager::MatchList fileList;
+ _engine->getSearchManager()->listMembersWithExtension(fileList, argv[1]);
+
+ for (SearchManager::MatchList::iterator iter = fileList.begin(); iter != fileList.end(); ++iter) {
+ fileName = iter->_value.name;
+ debugPrintf("Dumping %s\n", fileName.c_str());
+
+ in = iter->_value.arch->createReadStreamForMember(iter->_value.name);
+ dumpFile(in, fileName.c_str());
+ delete in;
+ }
return true;
}
diff --git a/engines/zvision/core/console.h b/engines/zvision/core/console.h
index 299bd6127f..a7bd88ebc3 100644
--- a/engines/zvision/core/console.h
+++ b/engines/zvision/core/console.h
@@ -46,6 +46,7 @@ private:
bool cmdSetPanoramaScale(int argc, const char **argv);
bool cmdLocation(int argc, const char **argv);
bool cmdDumpFile(int argc, const char **argv);
+ bool cmdDumpFiles(int argc, const char **argv);
};
} // End of namespace ZVision
diff --git a/engines/zvision/core/events.cpp b/engines/zvision/core/events.cpp
index 6cf0ae5d0d..7804130e2a 100644
--- a/engines/zvision/core/events.cpp
+++ b/engines/zvision/core/events.cpp
@@ -28,8 +28,9 @@
#include "zvision/graphics/cursors/cursor_manager.h"
#include "zvision/graphics/render_manager.h"
#include "zvision/scripting/script_manager.h"
-#include "zvision/core/menu.h"
+#include "zvision/scripting/menu.h"
#include "zvision/sound/zork_raw.h"
+#include "zvision/text/string_manager.h"
#include "common/events.h"
#include "common/system.h"
@@ -39,23 +40,50 @@
namespace ZVision {
+void ZVision::pushKeyToCheatBuf(uint8 key) {
+ for (int i = 0; i < KEYBUF_SIZE - 1; i++)
+ _cheatBuffer[i] = _cheatBuffer[i + 1];
+
+ _cheatBuffer[KEYBUF_SIZE - 1] = key;
+}
+
+bool ZVision::checkCode(const char *code) {
+ int codeLen = strlen(code);
+
+ if (codeLen > KEYBUF_SIZE)
+ return false;
+
+ for (int i = 0; i < codeLen; i++)
+ if (code[i] != _cheatBuffer[KEYBUF_SIZE - codeLen + i] && code[i] != '?')
+ return false;
+
+ return true;
+}
+
+uint8 ZVision::getBufferedKey(uint8 pos) {
+ if (pos >= KEYBUF_SIZE)
+ return 0;
+ else
+ return _cheatBuffer[KEYBUF_SIZE - pos - 1];
+}
+
void ZVision::shortKeys(Common::Event event) {
if (event.kbd.hasFlags(Common::KBD_CTRL)) {
switch (event.kbd.keycode) {
case Common::KEYCODE_s:
- if (getMenuBarEnable() & menuBar_Save)
+ if (_menu->getEnable() & kMenubarSave)
_scriptManager->changeLocation('g', 'j', 's', 'e', 0);
break;
case Common::KEYCODE_r:
- if (getMenuBarEnable() & menuBar_Restore)
+ if (_menu->getEnable() & kMenubarRestore)
_scriptManager->changeLocation('g', 'j', 'r', 'e', 0);
break;
case Common::KEYCODE_p:
- if (getMenuBarEnable() & menuBar_Settings)
+ if (_menu->getEnable() & kMenubarSettings)
_scriptManager->changeLocation('g', 'j', 'p', 'e', 0);
break;
case Common::KEYCODE_q:
- if (getMenuBarEnable() & menuBar_Exit)
+ if (_menu->getEnable() & kMenubarExit)
ifQuit();
break;
default:
@@ -70,11 +98,11 @@ void ZVision::cheatCodes(uint8 key) {
if (getGameId() == GID_GRANDINQUISITOR) {
if (checkCode("IMNOTDEAF")) {
// Unknown cheat
- showDebugMsg(Common::String::format("IMNOTDEAF cheat or debug, not implemented"));
+ _renderManager->showDebugMsg(Common::String::format("IMNOTDEAF cheat or debug, not implemented"));
}
if (checkCode("3100OPB")) {
- showDebugMsg(Common::String::format("Current location: %c%c%c%c",
+ _renderManager->showDebugMsg(Common::String::format("Current location: %c%c%c%c",
_scriptManager->getStateValue(StateKey_World),
_scriptManager->getStateValue(StateKey_Room),
_scriptManager->getStateValue(StateKey_Node),
@@ -91,9 +119,9 @@ void ZVision::cheatCodes(uint8 key) {
}
// There are 3 more cheats in script files:
- // - "EAT ME": gjcr.scr
- // - "WHOAMI": hp1e.scr
- // - "HUISOK": uh1f.scr
+ // - "WHOAMI": gjcr.scr
+ // - "HUISOK": hp1e.scr
+ // - "EAT ME": uh1f.scr
} else if (getGameId() == GID_NEMESIS) {
if (checkCode("CHLOE")) {
_scriptManager->changeLocation('t', 'm', '2', 'g', 0);
@@ -101,7 +129,7 @@ void ZVision::cheatCodes(uint8 key) {
}
if (checkCode("77MASSAVE")) {
- showDebugMsg(Common::String::format("Current location: %c%c%c%c",
+ _renderManager->showDebugMsg(Common::String::format("Current location: %c%c%c%c",
_scriptManager->getStateValue(StateKey_World),
_scriptManager->getStateValue(StateKey_Room),
_scriptManager->getStateValue(StateKey_Node),
@@ -130,21 +158,29 @@ void ZVision::cheatCodes(uint8 key) {
}
}
- if (checkCode("FRAME"))
- showDebugMsg(Common::String::format("FPS: ???, not implemented"));
+ if (checkCode("FRAME")) {
+ Common::String fpsStr = Common::String::format("FPS: %d", getFPS());
+ _renderManager->showDebugMsg(fpsStr);
+ }
+
+ if (checkCode("COMPUTERARCH"))
+ _renderManager->showDebugMsg("COMPUTERARCH: var-viewer not implemented");
+ // This cheat essentially toggles the GOxxxx cheat below
if (checkCode("XYZZY"))
_scriptManager->setStateValue(StateKey_DebugCheats, 1 - _scriptManager->getStateValue(StateKey_DebugCheats));
- if (checkCode("COMPUTERARCH"))
- showDebugMsg(Common::String::format("COMPUTERARCH: var-viewer not implemented"));
-
if (_scriptManager->getStateValue(StateKey_DebugCheats) == 1)
if (checkCode("GO????"))
_scriptManager->changeLocation(getBufferedKey(3),
getBufferedKey(2),
getBufferedKey(1),
getBufferedKey(0), 0);
+
+ // Show the Venus screen when "?" or "/" is pressed while inside the temple world
+ if (_scriptManager->getStateValue(StateKey_VenusEnable) == 1)
+ if (getBufferedKey(0) == 0xBF && _scriptManager->getStateValue(StateKey_World) == 't')
+ _scriptManager->changeLocation('g', 'j', 'h', 'e', 0);
}
void ZVision::processEvents() {
@@ -207,6 +243,11 @@ void ZVision::processEvents() {
_scriptManager->getStateValue(StateKey_KbdRotateSpeed)) * 2;
break;
+ case Common::KEYCODE_F10: {
+ Common::String fpsStr = Common::String::format("FPS: %d", getFPS());
+ _renderManager->showDebugMsg(fpsStr);
+ }
+ break;
default:
break;
}
@@ -279,26 +320,33 @@ void ZVision::onMouseMove(const Common::Point &pos) {
// |
// ^
- if (_workingWindow.contains(pos)) {
- cursorWasChanged = _scriptManager->onMouseMove(pos, imageCoord);
+ // Clip the horizontal mouse position to the working window
+ Common::Point clippedPos = pos;
+ clippedPos.x = CLIP<int16>(pos.x, _workingWindow.left + 1, _workingWindow.right - 1);
+
+ if (_workingWindow.contains(clippedPos)) {
+ cursorWasChanged = _scriptManager->onMouseMove(clippedPos, imageCoord);
RenderTable::RenderState renderState = _renderManager->getRenderTable()->getRenderState();
if (renderState == RenderTable::PANORAMA) {
- if (pos.x >= _workingWindow.left && pos.x < _workingWindow.left + ROTATION_SCREEN_EDGE_OFFSET) {
+ if (clippedPos.x >= _workingWindow.left && clippedPos.x < _workingWindow.left + ROTATION_SCREEN_EDGE_OFFSET) {
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
- if (mspeed <= 0)
- mspeed = 400 >> 4;
- _mouseVelocity = (((pos.x - (ROTATION_SCREEN_EDGE_OFFSET + _workingWindow.left)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7;
+ if (mspeed <= 0) {
+ mspeed = 25;
+ }
+ _mouseVelocity = MIN(((Common::Rational(mspeed, ROTATION_SCREEN_EDGE_OFFSET) * (clippedPos.x - _workingWindow.left)) - mspeed).toInt(), -1);
+
_cursorManager->changeCursor(CursorIndex_Left);
cursorWasChanged = true;
- } else if (pos.x <= _workingWindow.right && pos.x > _workingWindow.right - ROTATION_SCREEN_EDGE_OFFSET) {
+ } else if (clippedPos.x <= _workingWindow.right && clippedPos.x > _workingWindow.right - ROTATION_SCREEN_EDGE_OFFSET) {
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
- if (mspeed <= 0)
- mspeed = 400 >> 4;
- _mouseVelocity = (((pos.x - (_workingWindow.right - ROTATION_SCREEN_EDGE_OFFSET)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7;
+ if (mspeed <= 0) {
+ mspeed = 25;
+ }
+ _mouseVelocity = MAX((Common::Rational(mspeed, ROTATION_SCREEN_EDGE_OFFSET) * (clippedPos.x - _workingWindow.right + ROTATION_SCREEN_EDGE_OFFSET)).toInt(), 1);
_cursorManager->changeCursor(CursorIndex_Right);
cursorWasChanged = true;
@@ -306,21 +354,23 @@ void ZVision::onMouseMove(const Common::Point &pos) {
_mouseVelocity = 0;
}
} else if (renderState == RenderTable::TILT) {
- if (pos.y >= _workingWindow.top && pos.y < _workingWindow.top + ROTATION_SCREEN_EDGE_OFFSET) {
+ if (clippedPos.y >= _workingWindow.top && clippedPos.y < _workingWindow.top + ROTATION_SCREEN_EDGE_OFFSET) {
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
- if (mspeed <= 0)
- mspeed = 400 >> 4;
- _mouseVelocity = (((pos.y - (_workingWindow.top + ROTATION_SCREEN_EDGE_OFFSET)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7;
+ if (mspeed <= 0) {
+ mspeed = 25;
+ }
+ _mouseVelocity = MIN(((Common::Rational(mspeed, ROTATION_SCREEN_EDGE_OFFSET) * (pos.y - _workingWindow.top)) - mspeed).toInt(), -1);
_cursorManager->changeCursor(CursorIndex_UpArr);
cursorWasChanged = true;
- } else if (pos.y <= _workingWindow.bottom && pos.y > _workingWindow.bottom - ROTATION_SCREEN_EDGE_OFFSET) {
+ } else if (clippedPos.y <= _workingWindow.bottom && clippedPos.y > _workingWindow.bottom - ROTATION_SCREEN_EDGE_OFFSET) {
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
- if (mspeed <= 0)
- mspeed = 400 >> 4;
- _mouseVelocity = (((pos.y - (_workingWindow.bottom - ROTATION_SCREEN_EDGE_OFFSET)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7;
+ if (mspeed <= 0) {
+ mspeed = 25;
+ }
+ _mouseVelocity = MAX((Common::Rational(MAX_ROTATION_SPEED, ROTATION_SCREEN_EDGE_OFFSET) * (pos.y - _workingWindow.bottom + ROTATION_SCREEN_EDGE_OFFSET)).toInt(), 1);
_cursorManager->changeCursor(CursorIndex_DownArr);
cursorWasChanged = true;
@@ -441,4 +491,12 @@ uint8 ZVision::getZvisionKey(Common::KeyCode scummKeyCode) {
return 0;
}
+bool ZVision::ifQuit() {
+ if (_renderManager->askQuestion(_stringManager->getTextLine(StringManager::ZVISION_STR_EXITPROMT))) {
+ quitGame();
+ return true;
+ }
+ return false;
+}
+
} // End of namespace ZVision
diff --git a/engines/zvision/detection.cpp b/engines/zvision/detection.cpp
index ebf5bdcfdd..1eaff83413 100644
--- a/engines/zvision/detection.cpp
+++ b/engines/zvision/detection.cpp
@@ -26,7 +26,7 @@
#include "zvision/zvision.h"
#include "zvision/detection.h"
-#include "zvision/core/save_manager.h"
+#include "zvision/file/save_manager.h"
#include "zvision/scripting/script_manager.h"
#include "common/translation.h"
@@ -55,6 +55,11 @@ static const PlainGameDescriptor zVisionGames[] = {
namespace ZVision {
+#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
+#define GAMEOPTION_DOUBLE_FPS GUIO_GAMEOPTIONS2
+#define GAMEOPTION_ENABLE_VENUS GUIO_GAMEOPTIONS3
+#define GAMEOPTION_DISABLE_ANIM_WHILE_TURNING GUIO_GAMEOPTIONS4
+
static const ZVisionGameDescription gameDescriptions[] = {
{
@@ -66,7 +71,7 @@ static const ZVisionGameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
- GUIO1(GUIO_NONE)
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
},
GID_NEMESIS
},
@@ -80,7 +85,7 @@ static const ZVisionGameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_DEMO,
- GUIO1(GUIO_NONE)
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
},
GID_NEMESIS
},
@@ -94,35 +99,35 @@ static const ZVisionGameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
- GUIO1(GUIO_NONE)
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
},
GID_GRANDINQUISITOR
},
{
- // Zork Grand Inquisitor English demo version
+ // Zork Grand Inquisitor English DVD version
{
"zgi",
- "Demo",
- AD_ENTRY1s("SCRIPTS.ZFS", "71a2494fd2fb999347deb13401e9b998", 304239),
+ "DVD",
+ AD_ENTRY1s("SCRIPTS.ZFS", "03157a3399513bfaaf8dc6d5ab798b36", 8433326),
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DEMO,
- GUIO1(GUIO_NONE)
+ ADGF_NO_FLAGS,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
},
GID_GRANDINQUISITOR
},
{
- // Zork Grand Inquisitor English DVD version
+ // Zork Grand Inquisitor English demo version
{
"zgi",
- "DVD",
- AD_ENTRY1s("SCRIPTS.ZFS", "03157a3399513bfaaf8dc6d5ab798b36", 8433326),
+ "Demo",
+ AD_ENTRY1s("SCRIPTS.ZFS", "71a2494fd2fb999347deb13401e9b998", 304239),
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- GUIO1(GUIO_NONE)
+ ADGF_DEMO,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
},
GID_GRANDINQUISITOR
},
@@ -140,23 +145,53 @@ static const char *directoryGlobs[] = {
0
};
-static const ExtraGuiOption ZVisionExtraGuiOption = {
- _s("Use original save/load screens"),
- _s("Use the original save/load screens, instead of the ScummVM ones"),
- "originalsaveload",
- false
-};
+static const ADExtraGuiOptionsMap optionsList[] = {
+ {
+ GAMEOPTION_ORIGINAL_SAVELOAD,
+ {
+ _s("Use original save/load screens"),
+ _s("Use the original save/load screens, instead of the ScummVM ones"),
+ "originalsaveload",
+ false
+ }
+ },
+
+ {
+ GAMEOPTION_DOUBLE_FPS,
+ {
+ _s("Double FPS"),
+ _s("Halve the update delay"),
+ "doublefps",
+ false
+ }
+ },
+
+ {
+ GAMEOPTION_ENABLE_VENUS,
+ {
+ _s("Enable Venus"),
+ _s("Enable the Venus help system"),
+ "venusenabled",
+ true
+ }
+ },
-static const ExtraGuiOption ZVisionExtraGuiOption2 = {
- _s("Double FPS"),
- _s("Halve the update delay"),
- "doublefps",
- false
+ {
+ GAMEOPTION_DISABLE_ANIM_WHILE_TURNING,
+ {
+ _s("Disable animation while turning"),
+ _s("Disable animation while turning in panoramic mode"),
+ "noanimwhileturning",
+ false
+ }
+ },
+
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
class ZVisionMetaEngine : public AdvancedMetaEngine {
public:
- ZVisionMetaEngine() : AdvancedMetaEngine(ZVision::gameDescriptions, sizeof(ZVision::ZVisionGameDescription), zVisionGames) {
+ ZVisionMetaEngine() : AdvancedMetaEngine(ZVision::gameDescriptions, sizeof(ZVision::ZVisionGameDescription), zVisionGames, optionsList) {
_maxScanDepth = 2;
_directoryGlobs = directoryGlobs;
_singleid = "zvision";
@@ -172,7 +207,6 @@ public:
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
- virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const;
SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const;
void removeSaveState(const char *target, int slot) const;
@@ -223,13 +257,6 @@ bool ZVisionMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADG
return gd != 0;
}
-const ExtraGuiOptions ZVisionMetaEngine::getExtraGuiOptions(const Common::String &target) const {
- ExtraGuiOptions options;
- options.push_back(ZVisionExtraGuiOption);
- options.push_back(ZVisionExtraGuiOption2);
- return options;
-}
-
SaveStateList ZVisionMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
ZVision::SaveGameHeader header;
@@ -308,6 +335,11 @@ SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, in
if (successfulRead) {
SaveStateDescriptor desc(slot, header.saveName);
+ // Do not allow save slot 0 (used for auto-saving) to be deleted or
+ // overwritten.
+ desc.setDeletableFlag(slot != 0);
+ desc.setWriteProtectedFlag(slot == 0);
+
desc.setThumbnail(header.thumbnail);
if (header.version > 0) {
diff --git a/engines/zvision/core/save_manager.cpp b/engines/zvision/file/save_manager.cpp
index 20bd39fde5..042fafd38e 100644
--- a/engines/zvision/core/save_manager.cpp
+++ b/engines/zvision/file/save_manager.cpp
@@ -22,8 +22,8 @@
#include "common/scummsys.h"
-#include "zvision/core/save_manager.h"
#include "zvision/zvision.h"
+#include "zvision/file/save_manager.h"
#include "zvision/scripting/script_manager.h"
#include "zvision/graphics/render_manager.h"
@@ -78,9 +78,6 @@ bool SaveManager::scummVMSaveLoadDialog(bool isSave) {
}
void SaveManager::saveGame(uint slot, const Common::String &saveName) {
- // The games only support 20 slots
- //assert(slot <= 1 && slot <= 20);
-
Common::SaveFileManager *saveFileManager = g_system->getSavefileManager();
Common::OutSaveFile *file = saveFileManager->openForSaving(_engine->generateSaveFileName(slot));
@@ -90,6 +87,8 @@ void SaveManager::saveGame(uint slot, const Common::String &saveName) {
file->finalize();
delete file;
+
+ _lastSaveTime = g_system->getMillis();
}
void SaveManager::saveGame(uint slot, const Common::String &saveName, Common::MemoryWriteStreamDynamic *stream) {
@@ -102,6 +101,8 @@ void SaveManager::saveGame(uint slot, const Common::String &saveName, Common::Me
file->finalize();
delete file;
+
+ _lastSaveTime = g_system->getMillis();
}
void SaveManager::saveGameBuffered(uint slot, const Common::String &saveName) {
@@ -112,19 +113,10 @@ void SaveManager::saveGameBuffered(uint slot, const Common::String &saveName) {
}
void SaveManager::autoSave() {
- Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving(_engine->generateAutoSaveFileName());
-
- writeSaveGameHeader(file, "auto");
-
- _engine->getScriptManager()->serialize(file);
-
- // Cleanup
- file->finalize();
- delete file;
+ saveGame(0, "Auto save");
}
void SaveManager::writeSaveGameHeader(Common::OutSaveFile *file, const Common::String &saveName) {
-
file->writeUint32BE(SAVEGAME_ID);
// Write version
@@ -148,9 +140,6 @@ void SaveManager::writeSaveGameHeader(Common::OutSaveFile *file, const Common::S
}
Common::Error SaveManager::loadGame(uint slot) {
- // The games only support 20 slots
- //assert(slot <= 1 && slot <= 20);
-
Common::SeekableReadStream *saveFile = getSlotFile(slot);
if (saveFile == 0) {
return Common::kPathDoesNotExist;
@@ -226,7 +215,13 @@ bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &hea
// Check that the save version isn't newer than this binary
if (header.version > SAVE_VERSION) {
uint tempVersion = header.version;
- GUI::MessageDialog dialog(Common::String::format("This save file uses version %u, but this engine only supports up to version %d. You will need an updated version of the engine to use this save file.", tempVersion, SAVE_VERSION), "OK");
+ GUI::MessageDialog dialog(
+ Common::String::format(
+ "This save file uses version %u, but this engine only "
+ "supports up to version %d. You will need an updated version "
+ "of the engine to use this save file.", tempVersion, SAVE_VERSION
+ ),
+ "OK");
dialog.runModal();
}
diff --git a/engines/zvision/core/save_manager.h b/engines/zvision/file/save_manager.h
index 75841331e7..fc8db67566 100644
--- a/engines/zvision/core/save_manager.h
+++ b/engines/zvision/file/save_manager.h
@@ -48,13 +48,18 @@ struct SaveGameHeader {
class SaveManager {
public:
- SaveManager(ZVision *engine) : _engine(engine), _tempSave(NULL) {}
+ SaveManager(ZVision *engine) : _engine(engine), _tempSave(NULL), _lastSaveTime(0) {}
~SaveManager() {
flushSaveBuffer();
}
+ uint32 getLastSaveTime() const {
+ return _lastSaveTime;
+ }
+
private:
ZVision *_engine;
+ uint32 _lastSaveTime;
static const uint32 SAVEGAME_ID;
enum {
@@ -67,8 +72,7 @@ private:
public:
/**
* Called every room change. Saves the state of the room just before
- * we switched rooms. Uses ZVision::generateAutoSaveFileName() to
- * create the save file name.
+ * the room changes.
*/
void autoSave();
/**
diff --git a/engines/zvision/file/search_manager.cpp b/engines/zvision/file/search_manager.cpp
index 30c269c290..ec250ff648 100644
--- a/engines/zvision/file/search_manager.cpp
+++ b/engines/zvision/file/search_manager.cpp
@@ -169,8 +169,13 @@ void SearchManager::loadZix(const Common::String &name) {
line.trim();
if (line.matchString("----------*", true))
break;
- else if (line.matchString("DIR:*", true)) {
+ else if (line.matchString("DIR:*", true) || line.matchString("CD0:*", true) || line.matchString("CD1:*", true)) {
Common::String path(line.c_str() + 5);
+ // Check if INQUIS.ZIX refers to the ZGI folder, and check the game
+ // root folder instead
+ if (path.hasPrefix("zgi\\"))
+ path = Common::String(path.c_str() + 4);
+
Common::Archive *arc;
char tempPath[128];
strcpy(tempPath, path.c_str());
@@ -265,7 +270,7 @@ void SearchManager::addDir(const Common::String &name) {
void SearchManager::listDirRecursive(Common::List<Common::String> &_list, const Common::FSNode &fsNode, int depth) {
Common::FSList fsList;
- if ( fsNode.getChildren(fsList) ) {
+ if (fsNode.getChildren(fsList)) {
_list.push_back(fsNode.getPath());
@@ -275,4 +280,11 @@ void SearchManager::listDirRecursive(Common::List<Common::String> &_list, const
}
}
+void SearchManager::listMembersWithExtension(MatchList &fileList, Common::String extension) {
+ for (SearchManager::MatchList::iterator it = _files.begin(); it != _files.end(); ++it) {
+ if (it->_key.hasSuffix(extension))
+ fileList[it->_key] = it->_value;
+ }
+}
+
} // End of namespace ZVision
diff --git a/engines/zvision/file/search_manager.h b/engines/zvision/file/search_manager.h
index fdd70fd381..b9ed02ec13 100644
--- a/engines/zvision/file/search_manager.h
+++ b/engines/zvision/file/search_manager.h
@@ -47,25 +47,23 @@ public:
void loadZix(const Common::String &name);
-private:
-
- void listDirRecursive(Common::List<Common::String> &dirList, const Common::FSNode &fsNode, int depth);
-
struct Node {
Common::String name;
Common::Archive *arch;
};
- Common::List<Common::String> _dirList;
-
typedef Common::HashMap<Common::String, Node, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> MatchList;
- Common::List<Common::Archive *> _archList;
- MatchList _files;
-
- Common::String _root;
+ void listMembersWithExtension(MatchList &fileList, Common::String extension);
private:
+
+ void listDirRecursive(Common::List<Common::String> &dirList, const Common::FSNode &fsNode, int depth);
+
+ Common::List<Common::String> _dirList;
+ Common::List<Common::Archive *> _archList;
+ Common::String _root;
+ MatchList _files;
};
}
diff --git a/engines/zvision/graphics/cursors/cursor.cpp b/engines/zvision/graphics/cursors/cursor.cpp
index 07323b45c4..f32c68645d 100644
--- a/engines/zvision/graphics/cursors/cursor.cpp
+++ b/engines/zvision/graphics/cursors/cursor.cpp
@@ -36,35 +36,6 @@ ZorkCursor::ZorkCursor()
_hotspotY(0) {
}
-ZorkCursor::ZorkCursor(const Common::String &fileName)
- : _width(0),
- _height(0),
- _hotspotX(0),
- _hotspotY(0) {
- Common::File file;
- if (!file.open(fileName))
- return;
-
- uint32 magic = file.readUint32BE();
- if (magic != MKTAG('Z', 'C', 'R', '1')) {
- warning("%s is not a Zork Cursor file", fileName.c_str());
- return;
- }
-
- _hotspotX = file.readUint16LE();
- _hotspotY = file.readUint16LE();
- _width = file.readUint16LE();
- _height = file.readUint16LE();
-
- uint dataSize = _width * _height * sizeof(uint16);
- _surface.create(_width, _height, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
- uint32 bytesRead = file.read(_surface.getPixels(), dataSize);
- assert(bytesRead == dataSize);
-
- // Convert to RGB 565
- _surface.convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
-}
-
ZorkCursor::ZorkCursor(ZVision *engine, const Common::String &fileName)
: _width(0),
_height(0),
@@ -86,12 +57,15 @@ ZorkCursor::ZorkCursor(ZVision *engine, const Common::String &fileName)
_height = file.readUint16LE();
uint dataSize = _width * _height * sizeof(uint16);
- _surface.create(_width, _height, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
+ _surface.create(_width, _height, engine->_resourcePixelFormat);
uint32 bytesRead = file.read(_surface.getPixels(), dataSize);
assert(bytesRead == dataSize);
- // Convert to RGB 565
- _surface.convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+#ifndef SCUMM_LITTLE_ENDIAN
+ int16 *buffer = (int16 *)_surface.getPixels();
+ for (uint32 i = 0; i < dataSize / 2; ++i)
+ buffer[i] = FROM_LE_16(buffer[i]);
+#endif
}
ZorkCursor::ZorkCursor(const ZorkCursor &other) {
diff --git a/engines/zvision/graphics/cursors/cursor.h b/engines/zvision/graphics/cursors/cursor.h
index 0c1e99411f..6e0083520a 100644
--- a/engines/zvision/graphics/cursors/cursor.h
+++ b/engines/zvision/graphics/cursors/cursor.h
@@ -39,7 +39,6 @@ namespace ZVision {
class ZorkCursor {
public:
ZorkCursor();
- ZorkCursor(const Common::String &fileName);
ZorkCursor(ZVision *engine, const Common::String &fileName);
ZorkCursor(const ZorkCursor &other);
~ZorkCursor();
diff --git a/engines/zvision/graphics/cursors/cursor_manager.cpp b/engines/zvision/graphics/cursors/cursor_manager.cpp
index 92fd461c72..c364426bad 100644
--- a/engines/zvision/graphics/cursors/cursor_manager.cpp
+++ b/engines/zvision/graphics/cursors/cursor_manager.cpp
@@ -45,7 +45,7 @@ const char *CursorManager::_zNemCursorFileNames[NUM_CURSORS] = { "00act", "arrow
"hright", "hup", "00idle", "left", "right", "ssurr", "stilt", "turn", "up"
};
-CursorManager::CursorManager(ZVision *engine, const Graphics::PixelFormat *pixelFormat)
+CursorManager::CursorManager(ZVision *engine, const Graphics::PixelFormat pixelFormat)
: _engine(engine),
_pixelFormat(pixelFormat),
_cursorIsPushed(false),
@@ -106,7 +106,7 @@ void CursorManager::initialize() {
}
void CursorManager::changeCursor(const ZorkCursor &cursor) {
- CursorMan.replaceCursor(cursor.getSurface(), cursor.getWidth(), cursor.getHeight(), cursor.getHotspotX(), cursor.getHotspotY(), cursor.getKeyColor(), false, _pixelFormat);
+ CursorMan.replaceCursor(cursor.getSurface(), cursor.getWidth(), cursor.getHeight(), cursor.getHotspotX(), cursor.getHotspotY(), cursor.getKeyColor(), false, &_pixelFormat);
}
void CursorManager::cursorDown(bool pushed) {
diff --git a/engines/zvision/graphics/cursors/cursor_manager.h b/engines/zvision/graphics/cursors/cursor_manager.h
index bbfa085c23..35c605baf8 100644
--- a/engines/zvision/graphics/cursors/cursor_manager.h
+++ b/engines/zvision/graphics/cursors/cursor_manager.h
@@ -58,7 +58,7 @@ enum CursorIndex {
*/
class CursorManager {
public:
- CursorManager(ZVision *engine, const Graphics::PixelFormat *pixelFormat);
+ CursorManager(ZVision *engine, const Graphics::PixelFormat pixelFormat);
private:
static const int NUM_CURSORS = 18;
@@ -67,7 +67,7 @@ private:
ZorkCursor _cursors[NUM_CURSORS + 2][2];
ZVision *_engine;
- const Graphics::PixelFormat *_pixelFormat;
+ const Graphics::PixelFormat _pixelFormat;
bool _cursorIsPushed;
int _item;
int _lastitem;
diff --git a/engines/zvision/graphics/effects/fog.cpp b/engines/zvision/graphics/effects/fog.cpp
index f59e82a4a0..32a01915d3 100644
--- a/engines/zvision/graphics/effects/fog.cpp
+++ b/engines/zvision/graphics/effects/fog.cpp
@@ -31,7 +31,7 @@
namespace ZVision {
FogFx::FogFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, const Common::String &clouds):
- Effect(engine, key, region, ported) {
+ GraphicsEffect(engine, key, region, ported) {
_map = Map;
@@ -79,10 +79,10 @@ const Graphics::Surface *FogFx::draw(const Graphics::Surface &srcSubRect) {
if (it->inEffect) {
// Not 100% equivalent, but looks nice and not buggy
uint8 sr, sg, sb;
- _engine->_pixelFormat.colorToRGB(lineBuf[i], sr, sg, sb);
+ _engine->_resourcePixelFormat.colorToRGB(lineBuf[i], sr, sg, sb);
uint16 fogColor = *(uint16 *)_fog.getBasePtr((i + _pos) % _fog.w, j);
uint8 dr, dg, db;
- _engine->_pixelFormat.colorToRGB(_colorMap[fogColor & 0x1F], dr, dg, db);
+ _engine->_resourcePixelFormat.colorToRGB(_colorMap[fogColor & 0x1F], dr, dg, db);
uint16 fr = dr + sr;
if (fr > 255)
fr = 255;
@@ -92,7 +92,7 @@ const Graphics::Surface *FogFx::draw(const Graphics::Surface &srcSubRect) {
uint16 fb = db + sb;
if (fb > 255)
fb = 255;
- lineBuf[i] = _engine->_pixelFormat.RGBToColor(fr, fg, fb);
+ lineBuf[i] = _engine->_resourcePixelFormat.RGBToColor(fr, fg, fb);
}
cnt++;
if (cnt >= it->count) {
@@ -138,14 +138,14 @@ void FogFx::update() {
// Not 100% equivalent, but looks nice and not buggy
- _colorMap[31] = _engine->_pixelFormat.RGBToColor(_r << 3, _g << 3, _b << 3);
+ _colorMap[31] = _engine->_resourcePixelFormat.RGBToColor(_r << 3, _g << 3, _b << 3);
for (uint8 i = 0; i < 31; i++) {
float perc = (float)i / 31.0;
uint8 cr = (float)_r * perc;
uint8 cg = (float)_g * perc;
uint8 cb = (float)_b * perc;
- _colorMap[i] = _engine->_pixelFormat.RGBToColor(cr << 3, cg << 3, cb << 3);
+ _colorMap[i] = _engine->_resourcePixelFormat.RGBToColor(cr << 3, cg << 3, cb << 3);
}
}
diff --git a/engines/zvision/graphics/effects/fog.h b/engines/zvision/graphics/effects/fog.h
index 45d6f9596d..498347609e 100644
--- a/engines/zvision/graphics/effects/fog.h
+++ b/engines/zvision/graphics/effects/fog.h
@@ -23,13 +23,14 @@
#ifndef ZVISION_FOG_H
#define ZVISION_FOG_H
-#include "zvision/graphics/effect.h"
+#include "zvision/graphics/graphics_effect.h"
namespace ZVision {
class ZVision;
-class FogFx : public Effect {
+// Used by Zork: Nemesis for the mixing chamber gas effect in the gas puzzle (location tt5e, when the blinds are down)
+class FogFx : public GraphicsEffect {
public:
FogFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, const Common::String &clouds);
diff --git a/engines/zvision/graphics/effects/light.cpp b/engines/zvision/graphics/effects/light.cpp
index 00b3811d65..39341687f8 100644
--- a/engines/zvision/graphics/effects/light.cpp
+++ b/engines/zvision/graphics/effects/light.cpp
@@ -30,7 +30,7 @@
namespace ZVision {
LightFx::LightFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, int8 delta, int8 minD, int8 maxD):
- Effect(engine, key, region, ported) {
+ GraphicsEffect(engine, key, region, ported) {
_map = Map;
_delta = delta;
_up = true;
@@ -59,10 +59,10 @@ const Graphics::Surface *LightFx::draw(const Graphics::Surface &srcSubRect) {
if (_pos < 0) {
uint8 cc = ((-_pos) & 0x1F) << 3;
- dcolor = _engine->_pixelFormat.RGBToColor(cc, cc, cc);
+ dcolor = _engine->_resourcePixelFormat.RGBToColor(cc, cc, cc);
} else {
uint8 cc = (_pos & 0x1F) << 3;
- dcolor = _engine->_pixelFormat.RGBToColor(cc, cc, cc);
+ dcolor = _engine->_resourcePixelFormat.RGBToColor(cc, cc, cc);
}
for (uint16 j = 0; j < _surface.h; j++) {
diff --git a/engines/zvision/graphics/effects/light.h b/engines/zvision/graphics/effects/light.h
index ae87d66cb3..cd73a585ec 100644
--- a/engines/zvision/graphics/effects/light.h
+++ b/engines/zvision/graphics/effects/light.h
@@ -23,13 +23,13 @@
#ifndef LIGHTFX_H_INCLUDED
#define LIGHTFX_H_INCLUDED
-#include "zvision/graphics/effect.h"
+#include "zvision/graphics/graphics_effect.h"
namespace ZVision {
class ZVision;
-class LightFx : public Effect {
+class LightFx : public GraphicsEffect {
public:
LightFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, int8 delta, int8 minD = -127, int8 maxD = 127);
diff --git a/engines/zvision/graphics/effects/wave.cpp b/engines/zvision/graphics/effects/wave.cpp
index 1b3aa040e8..cec631611b 100644
--- a/engines/zvision/graphics/effects/wave.cpp
+++ b/engines/zvision/graphics/effects/wave.cpp
@@ -30,7 +30,7 @@
namespace ZVision {
WaveFx::WaveFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, int16 frames, int16 centerX, int16 centerY, float ampl, float waveln, float spd):
- Effect(engine, key, region, ported) {
+ GraphicsEffect(engine, key, region, ported) {
_frame = 0;
_frameCount = frames;
diff --git a/engines/zvision/graphics/effects/wave.h b/engines/zvision/graphics/effects/wave.h
index 2e813ed5b6..8e912372d7 100644
--- a/engines/zvision/graphics/effects/wave.h
+++ b/engines/zvision/graphics/effects/wave.h
@@ -24,13 +24,13 @@
#define WAVEFX_H_INCLUDED
#include "common/array.h"
-#include "zvision/graphics/effect.h"
+#include "zvision/graphics/graphics_effect.h"
namespace ZVision {
class ZVision;
-class WaveFx : public Effect {
+class WaveFx : public GraphicsEffect {
public:
WaveFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, int16 frames, int16 centerX, int16 centerY, float ampl, float waveln, float spd);
diff --git a/engines/zvision/graphics/effect.h b/engines/zvision/graphics/graphics_effect.h
index c6653c6037..bfa266b11d 100644
--- a/engines/zvision/graphics/effect.h
+++ b/engines/zvision/graphics/graphics_effect.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef EFFECT_H_INCLUDED
-#define EFFECT_H_INCLUDED
+#ifndef GRAPHICS_EFFECT_H_INCLUDED
+#define GRAPHICS_EFFECT_H_INCLUDED
#include "common/rect.h"
#include "common/list.h"
@@ -33,13 +33,13 @@ namespace ZVision {
class ZVision;
-class Effect {
+class GraphicsEffect {
public:
- Effect(ZVision *engine, uint32 key, Common::Rect region, bool ported) : _engine(engine), _key(key), _region(region), _ported(ported) {
- _surface.create(_region.width(), _region.height(), _engine->_pixelFormat);
+ GraphicsEffect(ZVision *engine, uint32 key, Common::Rect region, bool ported) : _engine(engine), _key(key), _region(region), _ported(ported) {
+ _surface.create(_region.width(), _region.height(), _engine->_resourcePixelFormat);
}
- virtual ~Effect() {}
+ virtual ~GraphicsEffect() {}
uint32 getKey() {
return _key;
@@ -80,4 +80,4 @@ typedef Common::List<EffectMapUnit> EffectMap;
} // End of namespace ZVision
-#endif // EFFECT_H_INCLUDED
+#endif // GRAPHICS_EFFECT_H_INCLUDED
diff --git a/engines/zvision/graphics/render_manager.cpp b/engines/zvision/graphics/render_manager.cpp
index b9305f5dcc..a1cc8ac53c 100644
--- a/engines/zvision/graphics/render_manager.cpp
+++ b/engines/zvision/graphics/render_manager.cpp
@@ -39,7 +39,7 @@
namespace ZVision {
-RenderManager::RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat)
+RenderManager::RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat, bool doubleFPS)
: _engine(engine),
_system(engine->_system),
_workingWidth(workingWindow.width()),
@@ -51,7 +51,8 @@ RenderManager::RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowH
_backgroundWidth(0),
_backgroundHeight(0),
_backgroundOffset(0),
- _renderTable(_workingWidth, _workingHeight) {
+ _renderTable(_workingWidth, _workingHeight),
+ _doubleFPS(doubleFPS) {
_backgroundSurface.create(_workingWidth, _workingHeight, _pixelFormat);
_effectSurface.create(_workingWidth, _workingHeight, _pixelFormat);
@@ -103,7 +104,8 @@ void RenderManager::renderSceneToScreen() {
post = (*it)->draw(_currentBackgroundImage.getSubArea(rect));
else
post = (*it)->draw(_effectSurface.getSubArea(rect));
- blitSurfaceToSurface(*post, _effectSurface, screenSpaceLocation.left, screenSpaceLocation.top);
+ Common::Rect empty;
+ blitSurfaceToSurface(*post, empty, _effectSurface, screenSpaceLocation.left, screenSpaceLocation.top);
screenSpaceLocation.clip(windowRect);
if (_backgroundSurfaceDirtyRect .isEmpty()) {
_backgroundSurfaceDirtyRect = screenSpaceLocation;
@@ -127,14 +129,29 @@ void RenderManager::renderSceneToScreen() {
}
if (!outWndDirtyRect.isEmpty()) {
- _system->copyRectToScreen(out->getBasePtr(outWndDirtyRect.left, outWndDirtyRect.top), out->pitch,
- outWndDirtyRect.left + _workingWindow.left,
- outWndDirtyRect.top + _workingWindow.top,
- outWndDirtyRect.width(),
- outWndDirtyRect.height());
+ Common::Rect rect(
+ outWndDirtyRect.left + _workingWindow.left,
+ outWndDirtyRect.top + _workingWindow.top,
+ outWndDirtyRect.left + _workingWindow.left + outWndDirtyRect.width(),
+ outWndDirtyRect.top + _workingWindow.top + outWndDirtyRect.height()
+ );
+ copyToScreen(*out, rect, outWndDirtyRect.left, outWndDirtyRect.top);
}
}
+void RenderManager::copyToScreen(const Graphics::Surface &surface, Common::Rect &rect, int16 srcLeft, int16 srcTop) {
+ // Convert the surface to RGB565, if needed
+ Graphics::Surface *outSurface = surface.convertTo(_engine->_screenPixelFormat);
+ _system->copyRectToScreen(outSurface->getBasePtr(srcLeft, srcTop),
+ outSurface->pitch,
+ rect.left,
+ rect.top,
+ rect.width(),
+ rect.height());
+ outSurface->free();
+ delete outSurface;
+}
+
void RenderManager::renderImageToBackground(const Common::String &fileName, int16 destX, int16 destY) {
Graphics::Surface surface;
readImageToSurface(fileName, surface);
@@ -162,97 +179,8 @@ void RenderManager::renderImageToBackground(const Common::String &fileName, int1
}
void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination) {
- Common::File file;
-
- if (!_engine->getSearchManager()->openFile(file, fileName)) {
- warning("Could not open file %s", fileName.c_str());
- return;
- }
-
- // Read the magic number
- // Some files are true TGA, while others are TGZ
- uint32 fileType = file.readUint32BE();
-
- uint32 imageWidth;
- uint32 imageHeight;
- Image::TGADecoder tga;
- uint16 *buffer;
bool isTransposed = _renderTable.getRenderState() == RenderTable::PANORAMA;
- // All ZVision images are in RGB 555
- Graphics::PixelFormat pixelFormat555 = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
- destination.format = pixelFormat555;
-
- bool isTGZ;
-
- // Check for TGZ files
- if (fileType == MKTAG('T', 'G', 'Z', '\0')) {
- isTGZ = true;
-
- // TGZ files have a header and then Bitmap data that is compressed with LZSS
- uint32 decompressedSize = file.readSint32LE();
- imageWidth = file.readSint32LE();
- imageHeight = file.readSint32LE();
-
- LzssReadStream lzssStream(&file);
- buffer = (uint16 *)(new uint16[decompressedSize]);
- lzssStream.read(buffer, decompressedSize);
- } else {
- isTGZ = false;
-
- // Reset the cursor
- file.seek(0);
-
- // Decode
- if (!tga.loadStream(file)) {
- warning("Error while reading TGA image");
- return;
- }
-
- Graphics::Surface tgaSurface = *(tga.getSurface());
- imageWidth = tgaSurface.w;
- imageHeight = tgaSurface.h;
-
- buffer = (uint16 *)tgaSurface.getPixels();
- }
-
- // Flip the width and height if transposed
- if (isTransposed) {
- uint16 temp = imageHeight;
- imageHeight = imageWidth;
- imageWidth = temp;
- }
-
- // If the destination internal buffer is the same size as what we're copying into it,
- // there is no need to free() and re-create
- if (imageWidth != destination.w || imageHeight != destination.h) {
- destination.create(imageWidth, imageHeight, pixelFormat555);
- }
-
- // If transposed, 'un-transpose' the data while copying it to the destination
- // Otherwise, just do a simple copy
- if (isTransposed) {
- uint16 *dest = (uint16 *)destination.getPixels();
-
- for (uint32 y = 0; y < imageHeight; ++y) {
- uint32 columnIndex = y * imageWidth;
-
- for (uint32 x = 0; x < imageWidth; ++x) {
- dest[columnIndex + x] = buffer[x * imageHeight + y];
- }
- }
- } else {
- memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * _pixelFormat.bytesPerPixel);
- }
-
- // Cleanup
- if (isTGZ) {
- delete[] buffer;
- } else {
- tga.destroy();
- }
-
- // Convert in place to RGB 565 from RGB 555
- destination.convertToInPlace(_pixelFormat);
+ readImageToSurface(fileName, destination, isTransposed);
}
void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination, bool transposed) {
@@ -272,8 +200,7 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
Image::TGADecoder tga;
uint16 *buffer;
// All ZVision images are in RGB 555
- Graphics::PixelFormat pixelFormat555 = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
- destination.format = pixelFormat555;
+ destination.format = _engine->_resourcePixelFormat;
bool isTGZ;
@@ -282,13 +209,17 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
isTGZ = true;
// TGZ files have a header and then Bitmap data that is compressed with LZSS
- uint32 decompressedSize = file.readSint32LE();
+ uint32 decompressedSize = file.readSint32LE() / 2;
imageWidth = file.readSint32LE();
imageHeight = file.readSint32LE();
LzssReadStream lzssStream(&file);
buffer = (uint16 *)(new uint16[decompressedSize]);
- lzssStream.read(buffer, decompressedSize);
+ lzssStream.read(buffer, 2 * decompressedSize);
+#ifndef SCUMM_LITTLE_ENDIAN
+ for (uint32 i = 0; i < decompressedSize; ++i)
+ buffer[i] = FROM_LE_16(buffer[i]);
+#endif
} else {
isTGZ = false;
@@ -318,7 +249,7 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
// If the destination internal buffer is the same size as what we're copying into it,
// there is no need to free() and re-create
if (imageWidth != destination.w || imageHeight != destination.h) {
- destination.create(imageWidth, imageHeight, pixelFormat555);
+ destination.create(imageWidth, imageHeight, _engine->_resourcePixelFormat);
}
// If transposed, 'un-transpose' the data while copying it to the destination
@@ -334,7 +265,7 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
}
}
} else {
- memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * _pixelFormat.bytesPerPixel);
+ memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * destination.format.bytesPerPixel);
}
// Cleanup
@@ -343,9 +274,6 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
} else {
tga.destroy();
}
-
- // Convert in place to RGB 565 from RGB 555
- destination.convertToInPlace(_pixelFormat);
}
const Common::Point RenderManager::screenSpaceToImageSpace(const Common::Point &point) {
@@ -459,10 +387,6 @@ void RenderManager::scaleBuffer(const void *src, void *dst, uint32 srcWidth, uin
}
void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y) {
-
- if (src.format != dst.format)
- return;
-
Common::Rect srcRect = _srcRect;
if (srcRect.isEmpty())
srcRect = Common::Rect(src.w, src.h);
@@ -473,8 +397,10 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
if (srcRect.isEmpty() || !srcRect.isValidRect())
return;
+ Graphics::Surface *srcAdapted = src.convertTo(dst.format);
+
// Copy srcRect from src surface to dst surface
- const byte *srcBuffer = (const byte *)src.getBasePtr(srcRect.left, srcRect.top);
+ const byte *srcBuffer = (const byte *)srcAdapted->getBasePtr(srcRect.left, srcRect.top);
int xx = _x;
int yy = _y;
@@ -484,8 +410,11 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
if (yy < 0)
yy = 0;
- if (_x >= dst.w || _y >= dst.h)
+ if (_x >= dst.w || _y >= dst.h) {
+ srcAdapted->free();
+ delete srcAdapted;
return;
+ }
byte *dstBuffer = (byte *)dst.getBasePtr(xx, yy);
@@ -493,17 +422,16 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
int32 h = srcRect.height();
for (int32 y = 0; y < h; y++) {
- memcpy(dstBuffer, srcBuffer, w * src.format.bytesPerPixel);
- srcBuffer += src.pitch;
+ memcpy(dstBuffer, srcBuffer, w * srcAdapted->format.bytesPerPixel);
+ srcBuffer += srcAdapted->pitch;
dstBuffer += dst.pitch;
}
+
+ srcAdapted->free();
+ delete srcAdapted;
}
void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y, uint32 colorkey) {
-
- if (src.format != dst.format)
- return;
-
Common::Rect srcRect = _srcRect;
if (srcRect.isEmpty())
srcRect = Common::Rect(src.w, src.h);
@@ -514,10 +442,11 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
if (srcRect.isEmpty() || !srcRect.isValidRect())
return;
- uint32 _keycolor = colorkey & ((1 << (src.format.bytesPerPixel << 3)) - 1);
+ Graphics::Surface *srcAdapted = src.convertTo(dst.format);
+ uint32 keycolor = colorkey & ((1 << (src.format.bytesPerPixel << 3)) - 1);
// Copy srcRect from src surface to dst surface
- const byte *srcBuffer = (const byte *)src.getBasePtr(srcRect.left, srcRect.top);
+ const byte *srcBuffer = (const byte *)srcAdapted->getBasePtr(srcRect.left, srcRect.top);
int xx = _x;
int yy = _y;
@@ -527,8 +456,11 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
if (yy < 0)
yy = 0;
- if (_x >= dst.w || _y >= dst.h)
+ if (_x >= dst.w || _y >= dst.h) {
+ srcAdapted->free();
+ delete srcAdapted;
return;
+ }
byte *dstBuffer = (byte *)dst.getBasePtr(xx, yy);
@@ -536,12 +468,12 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
int32 h = srcRect.height();
for (int32 y = 0; y < h; y++) {
- switch (src.format.bytesPerPixel) {
+ switch (srcAdapted->format.bytesPerPixel) {
case 1: {
const uint *srcTemp = (const uint *)srcBuffer;
uint *dstTemp = (uint *)dstBuffer;
for (int32 x = 0; x < w; x++) {
- if (*srcTemp != _keycolor)
+ if (*srcTemp != keycolor)
*dstTemp = *srcTemp;
srcTemp++;
dstTemp++;
@@ -553,7 +485,7 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
const uint16 *srcTemp = (const uint16 *)srcBuffer;
uint16 *dstTemp = (uint16 *)dstBuffer;
for (int32 x = 0; x < w; x++) {
- if (*srcTemp != _keycolor)
+ if (*srcTemp != keycolor)
*dstTemp = *srcTemp;
srcTemp++;
dstTemp++;
@@ -565,7 +497,7 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
const uint32 *srcTemp = (const uint32 *)srcBuffer;
uint32 *dstTemp = (uint32 *)dstBuffer;
for (int32 x = 0; x < w; x++) {
- if (*srcTemp != _keycolor)
+ if (*srcTemp != keycolor)
*dstTemp = *srcTemp;
srcTemp++;
dstTemp++;
@@ -576,35 +508,20 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
default:
break;
}
- srcBuffer += src.pitch;
+ srcBuffer += srcAdapted->pitch;
dstBuffer += dst.pitch;
}
-}
-
-void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y) {
- Common::Rect empt;
- blitSurfaceToSurface(src, empt, dst, x, y);
-}
-void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y, uint32 colorkey) {
- Common::Rect empt;
- blitSurfaceToSurface(src, empt, dst, x, y, colorkey);
+ srcAdapted->free();
+ delete srcAdapted;
}
-void RenderManager::blitSurfaceToBkg(const Graphics::Surface &src, int x, int y) {
+void RenderManager::blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, int32 colorkey) {
Common::Rect empt;
- blitSurfaceToSurface(src, empt, _currentBackgroundImage, x, y);
- Common::Rect dirty(src.w, src.h);
- dirty.translate(x, y);
- if (_backgroundDirtyRect.isEmpty())
- _backgroundDirtyRect = dirty;
+ if (colorkey >= 0)
+ blitSurfaceToSurface(src, empt, _currentBackgroundImage, x, y, colorkey);
else
- _backgroundDirtyRect.extend(dirty);
-}
-
-void RenderManager::blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, uint32 colorkey) {
- Common::Rect empt;
- blitSurfaceToSurface(src, empt, _currentBackgroundImage, x, y, colorkey);
+ blitSurfaceToSurface(src, empt, _currentBackgroundImage, x, y);
Common::Rect dirty(src.w, src.h);
dirty.translate(x, y);
if (_backgroundDirtyRect.isEmpty())
@@ -613,23 +530,10 @@ void RenderManager::blitSurfaceToBkg(const Graphics::Surface &src, int x, int y,
_backgroundDirtyRect.extend(dirty);
}
-void RenderManager::blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect) {
- if (src.w == _dstRect.width() && src.h == _dstRect.height())
- blitSurfaceToBkg(src, _dstRect.left, _dstRect.top);
- else {
- Graphics::Surface *tmp = new Graphics::Surface;
- tmp->create(_dstRect.width(), _dstRect.height(), src.format);
- scaleBuffer(src.getPixels(), tmp->getPixels(), src.w, src.h, src.format.bytesPerPixel, _dstRect.width(), _dstRect.height());
- blitSurfaceToBkg(*tmp, _dstRect.left, _dstRect.top);
- tmp->free();
- delete tmp;
- }
-}
-
-void RenderManager::blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect, uint32 colorkey) {
- if (src.w == _dstRect.width() && src.h == _dstRect.height())
+void RenderManager::blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect, int32 colorkey) {
+ if (src.w == _dstRect.width() && src.h == _dstRect.height()) {
blitSurfaceToBkg(src, _dstRect.left, _dstRect.top, colorkey);
- else {
+ } else {
Graphics::Surface *tmp = new Graphics::Surface;
tmp->create(_dstRect.width(), _dstRect.height(), src.format);
scaleBuffer(src.getPixels(), tmp->getPixels(), src.w, src.h, src.format.bytesPerPixel, _dstRect.width(), _dstRect.height());
@@ -639,20 +543,12 @@ void RenderManager::blitSurfaceToBkgScaled(const Graphics::Surface &src, const C
}
}
-void RenderManager::blitSurfaceToMenu(const Graphics::Surface &src, int x, int y) {
+void RenderManager::blitSurfaceToMenu(const Graphics::Surface &src, int x, int y, int32 colorkey) {
Common::Rect empt;
- blitSurfaceToSurface(src, empt, _menuSurface, x, y);
- Common::Rect dirty(src.w, src.h);
- dirty.translate(x, y);
- if (_menuSurfaceDirtyRect.isEmpty())
- _menuSurfaceDirtyRect = dirty;
+ if (colorkey >= 0)
+ blitSurfaceToSurface(src, empt, _menuSurface, x, y, colorkey);
else
- _menuSurfaceDirtyRect.extend(dirty);
-}
-
-void RenderManager::blitSurfaceToMenu(const Graphics::Surface &src, int x, int y, uint32 colorkey) {
- Common::Rect empt;
- blitSurfaceToSurface(src, empt, _menuSurface, x, y, colorkey);
+ blitSurfaceToSurface(src, empt, _menuSurface, x, y);
Common::Rect dirty(src.w, src.h);
dirty.translate(x, y);
if (_menuSurfaceDirtyRect.isEmpty())
@@ -676,28 +572,18 @@ Graphics::Surface *RenderManager::getBkgRect(Common::Rect &rect) {
return srf;
}
-Graphics::Surface *RenderManager::loadImage(Common::String &file) {
+Graphics::Surface *RenderManager::loadImage(Common::String file) {
Graphics::Surface *tmp = new Graphics::Surface;
readImageToSurface(file, *tmp);
return tmp;
}
-Graphics::Surface *RenderManager::loadImage(const char *file) {
- Common::String str = Common::String(file);
- return loadImage(str);
-}
-
-Graphics::Surface *RenderManager::loadImage(Common::String &file, bool transposed) {
+Graphics::Surface *RenderManager::loadImage(Common::String file, bool transposed) {
Graphics::Surface *tmp = new Graphics::Surface;
readImageToSurface(file, *tmp, transposed);
return tmp;
}
-Graphics::Surface *RenderManager::loadImage(const char *file, bool transposed) {
- Common::String str = Common::String(file);
- return loadImage(str, transposed);
-}
-
void RenderManager::prepareBackground() {
_backgroundDirtyRect.clip(_backgroundWidth, _backgroundHeight);
RenderTable::RenderState state = _renderTable.getRenderState();
@@ -788,12 +674,15 @@ void RenderManager::clearMenuSurface(const Common::Rect &r) {
void RenderManager::renderMenuToScreen() {
if (!_menuSurfaceDirtyRect.isEmpty()) {
_menuSurfaceDirtyRect.clip(Common::Rect(_menuSurface.w, _menuSurface.h));
- if (!_menuSurfaceDirtyRect.isEmpty())
- _system->copyRectToScreen(_menuSurface.getBasePtr(_menuSurfaceDirtyRect.left, _menuSurfaceDirtyRect.top), _menuSurface.pitch,
- _menuSurfaceDirtyRect.left + _menuArea.left,
- _menuSurfaceDirtyRect.top + _menuArea.top,
- _menuSurfaceDirtyRect.width(),
- _menuSurfaceDirtyRect.height());
+ if (!_menuSurfaceDirtyRect.isEmpty()) {
+ Common::Rect rect(
+ _menuSurfaceDirtyRect.left + _menuArea.left,
+ _menuSurfaceDirtyRect.top + _menuArea.top,
+ _menuSurfaceDirtyRect.left + _menuArea.left + _menuSurfaceDirtyRect.width(),
+ _menuSurfaceDirtyRect.top + _menuArea.top + _menuSurfaceDirtyRect.height()
+ );
+ copyToScreen(_menuSurface, rect, _menuSurfaceDirtyRect.left, _menuSurfaceDirtyRect.top);
+ }
_menuSurfaceDirtyRect = Common::Rect();
}
}
@@ -813,18 +702,9 @@ uint16 RenderManager::createSubArea(const Common::Rect &area) {
}
uint16 RenderManager::createSubArea() {
- _subid++;
-
- OneSubtitle sub;
- sub.redraw = false;
- sub.timer = -1;
- sub.todelete = false;
- sub.r = Common::Rect(_subtitleArea.left, _subtitleArea.top, _subtitleArea.right, _subtitleArea.bottom);
- sub.r.translate(-_workingWindow.left, -_workingWindow.top);
-
- _subsList[_subid] = sub;
-
- return _subid;
+ Common::Rect r(_subtitleArea.left, _subtitleArea.top, _subtitleArea.right, _subtitleArea.bottom);
+ r.translate(-_workingWindow.left, -_workingWindow.top);
+ return createSubArea(r);
}
void RenderManager::deleteSubArea(uint16 id) {
@@ -868,20 +748,23 @@ void RenderManager::processSubs(uint16 deltatime) {
OneSubtitle *sub = &it->_value;
if (sub->txt.size()) {
Graphics::Surface *rndr = new Graphics::Surface();
- rndr->create(sub->r.width(), sub->r.height(), _pixelFormat);
+ rndr->create(sub->r.width(), sub->r.height(), _engine->_resourcePixelFormat);
_engine->getTextRenderer()->drawTxtInOneLine(sub->txt, *rndr);
- blitSurfaceToSurface(*rndr, _subtitleSurface, sub->r.left - _subtitleArea.left + _workingWindow.left, sub->r.top - _subtitleArea.top + _workingWindow.top);
+ Common::Rect empty;
+ blitSurfaceToSurface(*rndr, empty, _subtitleSurface, sub->r.left - _subtitleArea.left + _workingWindow.left, sub->r.top - _subtitleArea.top + _workingWindow.top);
rndr->free();
delete rndr;
}
sub->redraw = false;
}
- _system->copyRectToScreen(_subtitleSurface.getPixels(), _subtitleSurface.pitch,
- _subtitleArea.left,
- _subtitleArea.top,
- _subtitleSurface.w,
- _subtitleSurface.h);
+ Common::Rect rect(
+ _subtitleArea.left,
+ _subtitleArea.top,
+ _subtitleArea.left + _subtitleSurface.w,
+ _subtitleArea.top + _subtitleSurface.h
+ );
+ copyToScreen(_subtitleSurface, rect, 0, 0);
}
}
@@ -889,7 +772,7 @@ Common::Point RenderManager::getBkgSize() {
return Common::Point(_backgroundWidth, _backgroundHeight);
}
-void RenderManager::addEffect(Effect *_effect) {
+void RenderManager::addEffect(GraphicsEffect *_effect) {
_effects.push_back(_effect);
}
@@ -1072,9 +955,221 @@ void RenderManager::markDirty() {
_backgroundDirtyRect = Common::Rect(_backgroundWidth, _backgroundHeight);
}
+#if 0
void RenderManager::bkgFill(uint8 r, uint8 g, uint8 b) {
_currentBackgroundImage.fillRect(Common::Rect(_currentBackgroundImage.w, _currentBackgroundImage.h), _currentBackgroundImage.format.RGBToColor(r, g, b));
markDirty();
}
+#endif
+
+void RenderManager::timedMessage(const Common::String &str, uint16 milsecs) {
+ uint16 msgid = createSubArea();
+ updateSubArea(msgid, str);
+ processSubs(0);
+ renderSceneToScreen();
+ deleteSubArea(msgid, milsecs);
+}
+
+bool RenderManager::askQuestion(const Common::String &str) {
+ uint16 msgid = createSubArea();
+ updateSubArea(msgid, str);
+ processSubs(0);
+ renderSceneToScreen();
+ _engine->stopClock();
+
+ int result = 0;
+
+ while (result == 0) {
+ Common::Event evnt;
+ while (_engine->getEventManager()->pollEvent(evnt)) {
+ if (evnt.type == Common::EVENT_KEYDOWN) {
+ switch (evnt.kbd.keycode) {
+ case Common::KEYCODE_y:
+ result = 2;
+ break;
+ case Common::KEYCODE_n:
+ result = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ _system->updateScreen();
+ if (_doubleFPS)
+ _system->delayMillis(33);
+ else
+ _system->delayMillis(66);
+ }
+ deleteSubArea(msgid);
+ _engine->startClock();
+ return result == 2;
+}
+
+void RenderManager::delayedMessage(const Common::String &str, uint16 milsecs) {
+ uint16 msgid = createSubArea();
+ updateSubArea(msgid, str);
+ processSubs(0);
+ renderSceneToScreen();
+ _engine->stopClock();
+
+ uint32 stopTime = _system->getMillis() + milsecs;
+ while (_system->getMillis() < stopTime) {
+ Common::Event evnt;
+ while (_engine->getEventManager()->pollEvent(evnt)) {
+ if (evnt.type == Common::EVENT_KEYDOWN &&
+ (evnt.kbd.keycode == Common::KEYCODE_SPACE ||
+ evnt.kbd.keycode == Common::KEYCODE_RETURN ||
+ evnt.kbd.keycode == Common::KEYCODE_ESCAPE))
+ break;
+ }
+ _system->updateScreen();
+ if (_doubleFPS)
+ _system->delayMillis(33);
+ else
+ _system->delayMillis(66);
+ }
+ deleteSubArea(msgid);
+ _engine->startClock();
+}
+
+void RenderManager::showDebugMsg(const Common::String &msg, int16 delay) {
+ uint16 msgid = createSubArea();
+ updateSubArea(msgid, msg);
+ deleteSubArea(msgid, delay);
+}
+
+void RenderManager::updateRotation() {
+ int16 _velocity = _engine->getMouseVelocity() + _engine->getKeyboardVelocity();
+ ScriptManager *scriptManager = _engine->getScriptManager();
+
+ if (_doubleFPS)
+ _velocity /= 2;
+
+ if (_velocity) {
+ RenderTable::RenderState renderState = _renderTable.getRenderState();
+ if (renderState == RenderTable::PANORAMA) {
+ int16 startPosition = scriptManager->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition + (_renderTable.getPanoramaReverse() ? -_velocity : _velocity);
+
+ int16 zeroPoint = _renderTable.getPanoramaZeroPoint();
+ if (startPosition >= zeroPoint && newPosition < zeroPoint)
+ scriptManager->setStateValue(StateKey_Rounds, scriptManager->getStateValue(StateKey_Rounds) - 1);
+ if (startPosition <= zeroPoint && newPosition > zeroPoint)
+ scriptManager->setStateValue(StateKey_Rounds, scriptManager->getStateValue(StateKey_Rounds) + 1);
+
+ int16 screenWidth = getBkgSize().x;
+ if (screenWidth)
+ newPosition %= screenWidth;
+
+ if (newPosition < 0)
+ newPosition += screenWidth;
+
+ setBackgroundPosition(newPosition);
+ } else if (renderState == RenderTable::TILT) {
+ int16 startPosition = scriptManager->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition + _velocity;
+
+ int16 screenHeight = getBkgSize().y;
+ int16 tiltGap = _renderTable.getTiltGap();
+
+ if (newPosition >= (screenHeight - tiltGap))
+ newPosition = screenHeight - tiltGap;
+ if (newPosition <= tiltGap)
+ newPosition = tiltGap;
+
+ setBackgroundPosition(newPosition);
+ }
+ }
+}
+
+void RenderManager::checkBorders() {
+ RenderTable::RenderState renderState = _renderTable.getRenderState();
+ if (renderState == RenderTable::PANORAMA) {
+ int16 startPosition = _engine->getScriptManager()->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition;
+
+ int16 screenWidth = getBkgSize().x;
+
+ if (screenWidth)
+ newPosition %= screenWidth;
+
+ if (newPosition < 0)
+ newPosition += screenWidth;
+
+ if (startPosition != newPosition)
+ setBackgroundPosition(newPosition);
+ } else if (renderState == RenderTable::TILT) {
+ int16 startPosition = _engine->getScriptManager()->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition;
+
+ int16 screenHeight = getBkgSize().y;
+ int16 tiltGap = _renderTable.getTiltGap();
+
+ if (newPosition >= (screenHeight - tiltGap))
+ newPosition = screenHeight - tiltGap;
+ if (newPosition <= tiltGap)
+ newPosition = tiltGap;
+
+ if (startPosition != newPosition)
+ setBackgroundPosition(newPosition);
+ }
+}
+
+void RenderManager::rotateTo(int16 _toPos, int16 _time) {
+ if (_renderTable.getRenderState() != RenderTable::PANORAMA)
+ return;
+
+ if (_time == 0)
+ _time = 1;
+
+ int32 maxX = getBkgSize().x;
+ int32 curX = getCurrentBackgroundOffset();
+ int32 dx = 0;
+
+ if (curX == _toPos)
+ return;
+
+ if (curX > _toPos) {
+ if (curX - _toPos > maxX / 2)
+ dx = (_toPos + (maxX - curX)) / _time;
+ else
+ dx = -(curX - _toPos) / _time;
+ } else {
+ if (_toPos - curX > maxX / 2)
+ dx = -((maxX - _toPos) + curX) / _time;
+ else
+ dx = (_toPos - curX) / _time;
+ }
+
+ _engine->stopClock();
+
+ for (int16 i = 0; i <= _time; i++) {
+ if (i == _time)
+ curX = _toPos;
+ else
+ curX += dx;
+
+ if (curX < 0)
+ curX = maxX - curX;
+ else if (curX >= maxX)
+ curX %= maxX;
+
+ setBackgroundPosition(curX);
+
+ prepareBackground();
+ renderSceneToScreen();
+
+ _system->updateScreen();
+
+ _system->delayMillis(500 / _time);
+ }
+
+ _engine->startClock();
+}
} // End of namespace ZVision
diff --git a/engines/zvision/graphics/render_manager.h b/engines/zvision/graphics/render_manager.h
index 29bbd8f411..c22f9a78c9 100644
--- a/engines/zvision/graphics/render_manager.h
+++ b/engines/zvision/graphics/render_manager.h
@@ -24,14 +24,14 @@
#define ZVISION_RENDER_MANAGER_H
#include "zvision/graphics/render_table.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
#include "common/rect.h"
#include "common/hashmap.h"
#include "graphics/surface.h"
-#include "effect.h"
+#include "graphics_effect.h"
class OSystem;
@@ -48,7 +48,7 @@ namespace ZVision {
class RenderManager {
public:
- RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat);
+ RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat, bool doubleFPS);
~RenderManager();
private:
@@ -61,7 +61,7 @@ private:
};
typedef Common::HashMap<uint16, OneSubtitle> SubtitleMap;
- typedef Common::List<Effect *> EffectsList;
+ typedef Common::List<GraphicsEffect *> EffectsList;
private:
ZVision *_engine;
@@ -137,6 +137,7 @@ private:
// Visual effects list
EffectsList _effects;
+ bool _doubleFPS;
public:
void initialize();
@@ -146,6 +147,8 @@ public:
*/
void renderSceneToScreen();
+ void copyToScreen(const Graphics::Surface &surface, Common::Rect &rect, int16 srcLeft, int16 srcTop);
+
/**
* Blits the image or a portion of the image to the background.
*
@@ -227,20 +230,15 @@ public:
// Blitting surface-to-surface methods
void blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int x, int y);
void blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y, uint32 colorkey);
- void blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y);
- void blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y, uint32 colorkey);
// Blitting surface-to-background methods
- void blitSurfaceToBkg(const Graphics::Surface &src, int x, int y);
- void blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, uint32 colorkey);
+ void blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, int32 colorkey = -1);
// Blitting surface-to-background methods with scale
- void blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect);
- void blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect, uint32 colorkey);
+ void blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect, int32 colorkey = -1);
// Blitting surface-to-menu methods
- void blitSurfaceToMenu(const Graphics::Surface &src, int x, int y);
- void blitSurfaceToMenu(const Graphics::Surface &src, int x, int y, uint32 colorkey);
+ void blitSurfaceToMenu(const Graphics::Surface &src, int x, int y, int32 colorkey = -1);
// Subtitles methods
@@ -265,10 +263,8 @@ public:
Graphics::Surface *getBkgRect(Common::Rect &rect);
// Load image into new surface
- Graphics::Surface *loadImage(const char *file);
- Graphics::Surface *loadImage(Common::String &file);
- Graphics::Surface *loadImage(const char *file, bool transposed);
- Graphics::Surface *loadImage(Common::String &file, bool transposed);
+ Graphics::Surface *loadImage(Common::String file);
+ Graphics::Surface *loadImage(Common::String file, bool transposed);
// Clear whole/area of menu surface
void clearMenuSurface();
@@ -281,8 +277,7 @@ public:
void prepareBackground();
/**
- * Reads an image file pixel data into a Surface buffer. In the process
- * it converts the pixel data from RGB 555 to RGB 565. Also, if the image
+ * Reads an image file pixel data into a Surface buffer. Also, if the image
* is transposed, it will un-transpose the pixel data. The function will
* call destination::create() if the dimensions of destination do not match
* up with the dimensions of the image.
@@ -293,8 +288,7 @@ public:
void readImageToSurface(const Common::String &fileName, Graphics::Surface &destination);
/**
- * Reads an image file pixel data into a Surface buffer. In the process
- * it converts the pixel data from RGB 555 to RGB 565. Also, if the image
+ * Reads an image file pixel data into a Surface buffer. Also, if the image
* is transposed, it will un-transpose the pixel data. The function will
* call destination::create() if the dimensions of destination do not match
* up with the dimensions of the image.
@@ -306,7 +300,7 @@ public:
void readImageToSurface(const Common::String &fileName, Graphics::Surface &destination, bool transposed);
// Add visual effect to effects list
- void addEffect(Effect *_effect);
+ void addEffect(GraphicsEffect *_effect);
// Delete effect(s) by ID (ID equal to slot of action:region that create this effect)
void deleteEffect(uint32 ID);
@@ -328,8 +322,19 @@ public:
// Mark whole background surface as dirty
void markDirty();
- // Fille background surface by color
+#if 0
+ // Fill background surface by color
void bkgFill(uint8 r, uint8 g, uint8 b);
+#endif
+
+ bool askQuestion(const Common::String &str);
+ void delayedMessage(const Common::String &str, uint16 milsecs);
+ void timedMessage(const Common::String &str, uint16 milsecs);
+ void showDebugMsg(const Common::String &msg, int16 delay = 3000);
+
+ void checkBorders();
+ void rotateTo(int16 to, int16 time);
+ void updateRotation();
};
} // End of namespace ZVision
diff --git a/engines/zvision/graphics/render_table.cpp b/engines/zvision/graphics/render_table.cpp
index c30e0bd472..df73247344 100644
--- a/engines/zvision/graphics/render_table.cpp
+++ b/engines/zvision/graphics/render_table.cpp
@@ -81,27 +81,6 @@ const Common::Point RenderTable::convertWarpedCoordToFlatCoord(const Common::Poi
return newPoint;
}
-uint16 mixTwoRGB(uint16 colorOne, uint16 colorTwo, float percentColorOne) {
- assert(percentColorOne < 1.0f);
-
- float rOne = float((colorOne & Graphics::ColorMasks<555>::kRedMask) >> Graphics::ColorMasks<555>::kRedShift);
- float rTwo = float((colorTwo & Graphics::ColorMasks<555>::kRedMask) >> Graphics::ColorMasks<555>::kRedShift);
- float gOne = float((colorOne & Graphics::ColorMasks<555>::kGreenMask) >> Graphics::ColorMasks<555>::kGreenShift);
- float gTwo = float((colorTwo & Graphics::ColorMasks<555>::kGreenMask) >> Graphics::ColorMasks<555>::kGreenShift);
- float bOne = float((colorOne & Graphics::ColorMasks<555>::kBlueMask) >> Graphics::ColorMasks<555>::kBlueShift);
- float bTwo = float((colorTwo & Graphics::ColorMasks<555>::kBlueMask) >> Graphics::ColorMasks<555>::kBlueShift);
-
- float rFinal = rOne * percentColorOne + rTwo * (1.0f - percentColorOne);
- float gFinal = gOne * percentColorOne + gTwo * (1.0f - percentColorOne);
- float bFinal = bOne * percentColorOne + bTwo * (1.0f - percentColorOne);
-
- uint16 returnColor = (byte(rFinal + 0.5f) << Graphics::ColorMasks<555>::kRedShift) |
- (byte(gFinal + 0.5f) << Graphics::ColorMasks<555>::kGreenShift) |
- (byte(bFinal + 0.5f) << Graphics::ColorMasks<555>::kBlueShift);
-
- return returnColor;
-}
-
void RenderTable::mutateImage(uint16 *sourceBuffer, uint16 *destBuffer, uint32 destWidth, const Common::Rect &subRect) {
uint32 destOffset = 0;
diff --git a/engines/zvision/module.mk b/engines/zvision/module.mk
index 00652f0824..93fba2879d 100644
--- a/engines/zvision/module.mk
+++ b/engines/zvision/module.mk
@@ -4,10 +4,9 @@ MODULE_OBJS := \
core/console.o \
core/clock.o \
core/events.o \
- core/menu.o \
- core/save_manager.o \
detection.o \
file/lzss_read_stream.o \
+ file/save_manager.o \
file/search_manager.o \
file/zfs_archive.o \
graphics/cursors/cursor_manager.o \
@@ -17,8 +16,6 @@ MODULE_OBJS := \
graphics/effects/wave.o \
graphics/render_manager.o \
graphics/render_table.o \
- graphics/subtitles.o \
- graphics/truetype_font.o \
scripting/actions.o \
scripting/control.o \
scripting/controls/fist_control.o \
@@ -32,19 +29,22 @@ MODULE_OBJS := \
scripting/controls/slot_control.o \
scripting/controls/titler_control.o \
scripting/inventory.o \
+ scripting/menu.o \
scripting/scr_file_handling.o \
scripting/script_manager.o \
- scripting/sidefx/animation_node.o \
- scripting/sidefx/distort_node.o \
- scripting/sidefx/music_node.o \
- scripting/sidefx/region_node.o \
- scripting/sidefx/syncsound_node.o \
- scripting/sidefx/timer_node.o \
- scripting/sidefx/ttytext_node.o \
+ scripting/effects/animation_effect.o \
+ scripting/effects/distort_effect.o \
+ scripting/effects/music_effect.o \
+ scripting/effects/region_effect.o \
+ scripting/effects/syncsound_effect.o \
+ scripting/effects/timer_effect.o \
+ scripting/effects/ttytext_effect.o \
sound/midi.o \
sound/zork_raw.o \
text/string_manager.o \
+ text/subtitles.o \
text/text.o \
+ text/truetype_font.o \
video/rlf_decoder.o \
video/video.o \
video/zork_avi_decoder.o \
diff --git a/engines/zvision/scripting/actions.cpp b/engines/zvision/scripting/actions.cpp
index 0422a2c028..a61fa26223 100644
--- a/engines/zvision/scripting/actions.cpp
+++ b/engines/zvision/scripting/actions.cpp
@@ -29,20 +29,21 @@
#include "zvision/graphics/render_manager.h"
#include "zvision/sound/zork_raw.h"
#include "zvision/video/zork_avi_decoder.h"
-#include "zvision/scripting/sidefx/timer_node.h"
-#include "zvision/scripting/sidefx/music_node.h"
-#include "zvision/scripting/sidefx/syncsound_node.h"
-#include "zvision/scripting/sidefx/animation_node.h"
-#include "zvision/scripting/sidefx/distort_node.h"
-#include "zvision/scripting/sidefx/ttytext_node.h"
-#include "zvision/scripting/sidefx/region_node.h"
+#include "zvision/file/save_manager.h"
+#include "zvision/scripting/menu.h"
+#include "zvision/scripting/effects/timer_effect.h"
+#include "zvision/scripting/effects/music_effect.h"
+#include "zvision/scripting/effects/syncsound_effect.h"
+#include "zvision/scripting/effects/animation_effect.h"
+#include "zvision/scripting/effects/distort_effect.h"
+#include "zvision/scripting/effects/ttytext_effect.h"
+#include "zvision/scripting/effects/region_effect.h"
#include "zvision/scripting/controls/titler_control.h"
#include "zvision/graphics/render_table.h"
-#include "zvision/graphics/effect.h"
+#include "zvision/graphics/graphics_effect.h"
#include "zvision/graphics/effects/fog.h"
#include "zvision/graphics/effects/light.h"
#include "zvision/graphics/effects/wave.h"
-#include "zvision/core/save_manager.h"
#include "zvision/graphics/cursors/cursor_manager.h"
#include "common/file.h"
@@ -105,8 +106,8 @@ ActionAttenuate::ActionAttenuate(ZVision *engine, int32 slotkey, const Common::S
}
bool ActionAttenuate::execute() {
- SideFX *fx = _engine->getScriptManager()->getSideFX(_key);
- if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) {
+ ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(_key);
+ if (fx && fx->getType() == ScriptingEffect::SCRIPTING_EFFECT_AUDIO) {
MusicNode *mus = (MusicNode *)fx;
mus->setVolume(255 - (abs(_attenuation) >> 7));
}
@@ -156,8 +157,8 @@ ActionCrossfade::ActionCrossfade(ZVision *engine, int32 slotkey, const Common::S
bool ActionCrossfade::execute() {
if (_keyOne) {
- SideFX *fx = _engine->getScriptManager()->getSideFX(_keyOne);
- if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) {
+ ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(_keyOne);
+ if (fx && fx->getType() == ScriptingEffect::SCRIPTING_EFFECT_AUDIO) {
MusicNode *mus = (MusicNode *)fx;
if (_oneStartVolume >= 0)
mus->setVolume((_oneStartVolume * 255) / 100);
@@ -167,8 +168,8 @@ bool ActionCrossfade::execute() {
}
if (_keyTwo) {
- SideFX *fx = _engine->getScriptManager()->getSideFX(_keyTwo);
- if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) {
+ ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(_keyTwo);
+ if (fx && fx->getType() == ScriptingEffect::SCRIPTING_EFFECT_AUDIO) {
MusicNode *mus = (MusicNode *)fx;
if (_twoStartVolume >= 0)
mus->setVolume((_twoStartVolume * 255) / 100);
@@ -243,23 +244,6 @@ bool ActionDisableControl::execute() {
}
//////////////////////////////////////////////////////////////////////////////
-// ActionDisableVenus
-//////////////////////////////////////////////////////////////////////////////
-
-ActionDisableVenus::ActionDisableVenus(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
- _key = 0;
-
- sscanf(line.c_str(), "%d", &_key);
-}
-
-bool ActionDisableVenus::execute() {
- _engine->getScriptManager()->setStateValue(_key, 0);
-
- return true;
-}
-
-//////////////////////////////////////////////////////////////////////////////
// ActionDisplayMessage
//////////////////////////////////////////////////////////////////////////////
@@ -295,7 +279,7 @@ bool ActionDissolve::execute() {
}
//////////////////////////////////////////////////////////////////////////////
-// ActionDistort
+// ActionDistort - only used by Zork: Nemesis for the "treatment" puzzle in the Sanitarium (aj30)
//////////////////////////////////////////////////////////////////////////////
ActionDistort::ActionDistort(ZVision *engine, int32 slotkey, const Common::String &line) :
@@ -363,7 +347,7 @@ ActionInventory::ActionInventory(ZVision *engine, int32 slotkey, const Common::S
_key = 0;
char buf[25];
- sscanf(line.c_str(), "%25s %d", buf, &_key);
+ sscanf(line.c_str(), "%24s %d", buf, &_key);
if (strcmp(buf, "add") == 0) {
_type = 0;
@@ -406,7 +390,7 @@ bool ActionInventory::execute() {
}
//////////////////////////////////////////////////////////////////////////////
-// ActionKill
+// ActionKill - only used by ZGI
//////////////////////////////////////////////////////////////////////////////
ActionKill::ActionKill(ZVision *engine, int32 slotkey, const Common::String &line) :
@@ -414,31 +398,31 @@ ActionKill::ActionKill(ZVision *engine, int32 slotkey, const Common::String &lin
_key = 0;
_type = 0;
char keytype[25];
- sscanf(line.c_str(), "%25s", keytype);
+ sscanf(line.c_str(), "%24s", keytype);
if (keytype[0] == '"') {
if (!scumm_stricmp(keytype, "\"ANIM\""))
- _type = SideFX::SIDEFX_ANIM;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_ANIM;
else if (!scumm_stricmp(keytype, "\"AUDIO\""))
- _type = SideFX::SIDEFX_AUDIO;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_AUDIO;
else if (!scumm_stricmp(keytype, "\"DISTORT\""))
- _type = SideFX::SIDEFX_DISTORT;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_DISTORT;
else if (!scumm_stricmp(keytype, "\"PANTRACK\""))
- _type = SideFX::SIDEFX_PANTRACK;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_PANTRACK;
else if (!scumm_stricmp(keytype, "\"REGION\""))
- _type = SideFX::SIDEFX_REGION;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_REGION;
else if (!scumm_stricmp(keytype, "\"TIMER\""))
- _type = SideFX::SIDEFX_TIMER;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_TIMER;
else if (!scumm_stricmp(keytype, "\"TTYTEXT\""))
- _type = SideFX::SIDEFX_TTYTXT;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_TTYTXT;
else if (!scumm_stricmp(keytype, "\"ALL\""))
- _type = SideFX::SIDEFX_ALL;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_ALL;
} else
_key = atoi(keytype);
}
bool ActionKill::execute() {
if (_type)
- _engine->getScriptManager()->killSideFxType((SideFX::SideFXType)_type);
+ _engine->getScriptManager()->killSideFxType((ScriptingEffect::ScriptingEffectType)_type);
else
_engine->getScriptManager()->killSideFx(_key);
return true;
@@ -456,7 +440,7 @@ ActionMenuBarEnable::ActionMenuBarEnable(ZVision *engine, int32 slotkey, const C
}
bool ActionMenuBarEnable::execute() {
- _engine->menuBarEnable(_menus);
+ _engine->getMenuHandler()->setEnable(_menus);
return true;
}
@@ -475,9 +459,11 @@ ActionMusic::ActionMusic(ZVision *engine, int32 slotkey, const Common::String &l
uint loop = 0;
uint volume = 255;
- sscanf(line.c_str(), "%u %25s %u %u", &type, fileNameBuffer, &loop, &volume);
+ sscanf(line.c_str(), "%u %24s %u %u", &type, fileNameBuffer, &loop, &volume);
- // type 4 are midi sound effect files
+ // Type 4 actions are MIDI commands, not files. These are only used by
+ // Zork: Nemesis, for the flute and piano puzzles (tj4e and ve6f, as well
+ // as vr)
if (type == 4) {
_midi = true;
int note;
@@ -577,14 +563,14 @@ ActionPreloadAnimation::ActionPreloadAnimation(ZVision *engine, int32 slotkey, c
char fileName[25];
- // The two %*u are always 0 and dont seem to have a use
- sscanf(line.c_str(), "%25s %*u %*u %d %d", fileName, &_mask, &_framerate);
+ // The two %*u are usually 0 and dont seem to have a use
+ sscanf(line.c_str(), "%24s %*u %*u %d %d", fileName, &_mask, &_framerate);
- if (_mask > 0) {
- byte r, g, b;
- Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(_mask, r, g, b);
- _mask = _engine->_pixelFormat.RGBToColor(r, g, b);
- }
+ // Mask 0 means "no transparency" in this case. Since we use a common blitting
+ // code for images and animations, we set it to -1 to avoid confusion with
+ // color 0, which is used as a mask in some images
+ if (_mask == 0)
+ _mask = -1;
_fileName = Common::String(fileName);
}
@@ -594,10 +580,10 @@ ActionPreloadAnimation::~ActionPreloadAnimation() {
}
bool ActionPreloadAnimation::execute() {
- AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_slotKey);
+ AnimationEffect *nod = (AnimationEffect *)_engine->getScriptManager()->getSideFX(_slotKey);
if (!nod) {
- nod = new AnimationNode(_engine, _slotKey, _fileName, _mask, _framerate, false);
+ nod = new AnimationEffect(_engine, _slotKey, _fileName, _mask, _framerate, false);
_engine->getScriptManager()->addSideFX(nod);
} else
nod->stop();
@@ -617,9 +603,9 @@ ActionUnloadAnimation::ActionUnloadAnimation(ZVision *engine, int32 slotkey, con
}
bool ActionUnloadAnimation::execute() {
- AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_key);
+ AnimationEffect *nod = (AnimationEffect *)_engine->getScriptManager()->getSideFX(_key);
- if (nod && nod->getType() == SideFX::SIDEFX_ANIM)
+ if (nod && nod->getType() == ScriptingEffect::SCRIPTING_EFFECT_ANIM)
_engine->getScriptManager()->deleteSideFx(_key);
return true;
@@ -645,14 +631,14 @@ ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, int32 slotkey, const C
// The two %*u are always 0 and dont seem to have a use
sscanf(line.c_str(),
- "%25s %u %u %u %u %u %u %d %*u %*u %d %d",
+ "%24s %u %u %u %u %u %u %d %*u %*u %d %d",
fileName, &_x, &_y, &_x2, &_y2, &_start, &_end, &_loopCount, &_mask, &_framerate);
- if (_mask > 0) {
- byte r, g, b;
- Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(_mask, r, g, b);
- _mask = _engine->_pixelFormat.RGBToColor(r, g, b);
- }
+ // Mask 0 means "no transparency" in this case. Since we use a common blitting
+ // code for images and animations, we set it to -1 to avoid confusion with
+ // color 0, which is used as a mask in some images
+ if (_mask == 0)
+ _mask = -1;
_fileName = Common::String(fileName);
}
@@ -662,10 +648,10 @@ ActionPlayAnimation::~ActionPlayAnimation() {
}
bool ActionPlayAnimation::execute() {
- AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_slotKey);
+ AnimationEffect *nod = (AnimationEffect *)_engine->getScriptManager()->getSideFX(_slotKey);
if (!nod) {
- nod = new AnimationNode(_engine, _slotKey, _fileName, _mask, _framerate);
+ nod = new AnimationEffect(_engine, _slotKey, _fileName, _mask, _framerate);
_engine->getScriptManager()->addSideFX(nod);
} else
nod->stop();
@@ -697,7 +683,7 @@ ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, int32 sl
}
bool ActionPlayPreloadAnimation::execute() {
- AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_controlKey);
+ AnimationEffect *nod = (AnimationEffect *)_engine->getScriptManager()->getSideFX(_controlKey);
if (nod)
nod->addPlayNode(_slotKey, _x1, _y1, _x2, _y2, _startFrame, _endFrame, _loopCount);
@@ -716,7 +702,7 @@ bool ActionQuit::execute() {
}
//////////////////////////////////////////////////////////////////////////////
-// ActionRegion
+// ActionRegion - only used by Zork: Nemesis
//////////////////////////////////////////////////////////////////////////////
ActionRegion::ActionRegion(ZVision *engine, int32 slotkey, const Common::String &line) :
@@ -745,13 +731,13 @@ bool ActionRegion::execute() {
if (_engine->getScriptManager()->getSideFX(_slotKey))
return true;
- Effect *effct = NULL;
+ GraphicsEffect *effect = NULL;
switch (_type) {
case 0: {
uint16 centerX, centerY, frames;
double amplitude, waveln, speed;
sscanf(_custom.c_str(), "%hu,%hu,%hu,%lf,%lf,%lf,", &centerX, &centerY, &frames, &amplitude, &waveln, &speed);
- effct = new WaveFx(_engine, _slotKey, _rect, _unk1, frames, centerX, centerY, amplitude, waveln, speed);
+ effect = new WaveFx(_engine, _slotKey, _rect, _unk1, frames, centerX, centerY, amplitude, waveln, speed);
}
break;
case 1: {
@@ -763,7 +749,7 @@ bool ActionRegion::execute() {
int8 minD;
int8 maxD;
EffectMap *_map = _engine->getRenderManager()->makeEffectMap(Common::Point(aX, aY), aD, _rect, &minD, &maxD);
- effct = new LightFx(_engine, _slotKey, _rect, _unk1, _map, atoi(_custom.c_str()), minD, maxD);
+ effect = new LightFx(_engine, _slotKey, _rect, _unk1, _map, atoi(_custom.c_str()), minD, maxD);
}
break;
case 9: {
@@ -779,16 +765,16 @@ bool ActionRegion::execute() {
_rect.setHeight(tempMask.h);
EffectMap *_map = _engine->getRenderManager()->makeEffectMap(tempMask, 0);
- effct = new FogFx(_engine, _slotKey, _rect, _unk1, _map, Common::String(buf));
+ effect = new FogFx(_engine, _slotKey, _rect, _unk1, _map, Common::String(buf));
}
break;
default:
break;
}
- if (effct) {
- _engine->getScriptManager()->addSideFX(new RegionNode(_engine, _slotKey, effct, _delay));
- _engine->getRenderManager()->addEffect(effct);
+ if (effect) {
+ _engine->getScriptManager()->addSideFX(new RegionNode(_engine, _slotKey, effect, _delay));
+ _engine->getRenderManager()->addEffect(effect);
}
return true;
@@ -846,7 +832,7 @@ ActionRotateTo::ActionRotateTo(ZVision *engine, int32 slotkey, const Common::Str
}
bool ActionRotateTo::execute() {
- _engine->rotateTo(_toPos, _time);
+ _engine->getRenderManager()->rotateTo(_toPos, _time);
return true;
}
@@ -861,21 +847,12 @@ ActionSetPartialScreen::ActionSetPartialScreen(ZVision *engine, int32 slotkey, c
_y = 0;
char fileName[25];
- int color;
- sscanf(line.c_str(), "%u %u %25s %*u %d", &_x, &_y, fileName, &color);
+ sscanf(line.c_str(), "%u %u %24s %*u %d", &_x, &_y, fileName, &_backgroundColor);
_fileName = Common::String(fileName);
- if (color >= 0) {
- byte r, g, b;
- Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(color, r, g, b);
- _backgroundColor = _engine->_pixelFormat.RGBToColor(r, g, b);
- } else {
- _backgroundColor = color;
- }
-
- if (color > 65535) {
+ if (_backgroundColor > 65535) {
warning("Background color for ActionSetPartialScreen is bigger than a uint16");
}
}
@@ -907,7 +884,7 @@ bool ActionSetPartialScreen::execute() {
ActionSetScreen::ActionSetScreen(ZVision *engine, int32 slotkey, const Common::String &line) :
ResultAction(engine, slotkey) {
char fileName[25];
- sscanf(line.c_str(), "%25s", fileName);
+ sscanf(line.c_str(), "%24s", fileName);
_fileName = Common::String(fileName);
}
@@ -919,24 +896,6 @@ bool ActionSetScreen::execute() {
}
//////////////////////////////////////////////////////////////////////////////
-// ActionSetVenus
-//////////////////////////////////////////////////////////////////////////////
-
-ActionSetVenus::ActionSetVenus(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
- _key = 0;
-
- sscanf(line.c_str(), "%d", &_key);
-}
-
-bool ActionSetVenus::execute() {
- if (_engine->getScriptManager()->getStateValue(_key))
- _engine->getScriptManager()->setStateValue(StateKey_Venus, _key);
-
- return true;
-}
-
-//////////////////////////////////////////////////////////////////////////////
// ActionStop
//////////////////////////////////////////////////////////////////////////////
@@ -966,7 +925,7 @@ ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotkey, const Commo
char fileName[25];
uint skipline = 0; //skipline - render video with skip every second line, not skippable.
- sscanf(line.c_str(), "%25s %u %u %u %u %u %u", fileName, &_x1, &_y1, &_x2, &_y2, &_flags, &skipline);
+ sscanf(line.c_str(), "%24s %u %u %u %u %u %u", fileName, &_x1, &_y1, &_x2, &_y2, &_flags, &skipline);
_fileName = Common::String(fileName);
_skippable = true;
@@ -1017,23 +976,19 @@ ActionSyncSound::ActionSyncSound(ZVision *engine, int32 slotkey, const Common::S
char fileName[25];
int notUsed = 0;
- sscanf(line.c_str(), "%d %d %25s", &_syncto, &notUsed, fileName);
+ sscanf(line.c_str(), "%d %d %24s", &_syncto, &notUsed, fileName);
_fileName = Common::String(fileName);
}
bool ActionSyncSound::execute() {
- SideFX *fx = _engine->getScriptManager()->getSideFX(_syncto);
+ ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(_syncto);
if (!fx)
return true;
- if (!(fx->getType() & SideFX::SIDEFX_ANIM))
+ if (!(fx->getType() & ScriptingEffect::SCRIPTING_EFFECT_ANIM))
return true;
- AnimationNode *animnode = (AnimationNode *)fx;
- if (animnode->getFrameDelay() > 200) // Hack for fix incorrect framedelay in some animpreload
- animnode->setNewFrameDelay(66); // ~15fps
-
_engine->getScriptManager()->addSideFX(new SyncSoundNode(_engine, _slotKey, _fileName, _syncto));
return true;
}
diff --git a/engines/zvision/scripting/actions.h b/engines/zvision/scripting/actions.h
index 292e25e19c..8d43309b74 100644
--- a/engines/zvision/scripting/actions.h
+++ b/engines/zvision/scripting/actions.h
@@ -124,14 +124,6 @@ private:
uint8 _action;
};
-class ActionDebug : public ResultAction {
-public:
- ActionDebug(ZVision *engine, int32 slotkey, const Common::String &line);
- bool execute();
-
-private:
-};
-
class ActionDelayRender : public ResultAction {
public:
ActionDelayRender(ZVision *engine, int32 slotkey, const Common::String &line);
@@ -150,15 +142,6 @@ private:
uint32 _key;
};
-class ActionDisableVenus : public ResultAction {
-public:
- ActionDisableVenus(ZVision *engine, int32 slotkey, const Common::String &line);
- bool execute();
-
-private:
- int32 _key;
-};
-
class ActionDisplayMessage : public ResultAction {
public:
ActionDisplayMessage(ZVision *engine, int32 slotkey, const Common::String &line);
@@ -338,7 +321,7 @@ private:
uint16 _unk2;
};
-// TODO: See if this exists in ZGI. It doesn't in ZNem
+// Only used by ZGI (locations cd6e, cd6k, dg2f, dg4e, dv1j)
class ActionUnloadAnimation : public ResultAction {
public:
ActionUnloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line);
@@ -397,15 +380,6 @@ private:
Common::String _fileName;
};
-class ActionSetVenus : public ResultAction {
-public:
- ActionSetVenus(ZVision *engine, int32 slotkey, const Common::String &line);
- bool execute();
-
-private:
- int32 _key;
-};
-
class ActionStop : public ResultAction {
public:
ActionStop(ZVision *engine, int32 slotkey, const Common::String &line);
diff --git a/engines/zvision/scripting/control.cpp b/engines/zvision/scripting/control.cpp
index 127f35ef12..81123eb99b 100644
--- a/engines/zvision/scripting/control.cpp
+++ b/engines/zvision/scripting/control.cpp
@@ -72,6 +72,7 @@ void Control::parsePanoramaControl(ZVision *engine, Common::SeekableReadStream &
renderTable->generateRenderTable();
}
+// Only used in Zork Nemesis, handles tilt controls (ZGI doesn't have a tilt view)
void Control::parseTiltControl(ZVision *engine, Common::SeekableReadStream &stream) {
RenderTable *renderTable = engine->getRenderManager()->getRenderTable();
renderTable->setRenderState(RenderTable::TILT);
diff --git a/engines/zvision/scripting/control.h b/engines/zvision/scripting/control.h
index 803d0cf1ce..108b83fd00 100644
--- a/engines/zvision/scripting/control.h
+++ b/engines/zvision/scripting/control.h
@@ -36,6 +36,11 @@ namespace ZVision {
class ZVision;
+/**
+ * The base class for all Controls.
+ *
+ * Controls are the things that the user interacts with. Ex: A lever on the door
+ */
class Control {
public:
diff --git a/engines/zvision/scripting/controls/fist_control.cpp b/engines/zvision/scripting/controls/fist_control.cpp
index 34a64b4298..4a8e8b1bbd 100644
--- a/engines/zvision/scripting/controls/fist_control.cpp
+++ b/engines/zvision/scripting/controls/fist_control.cpp
@@ -46,10 +46,6 @@ FistControl::FistControl(ZVision *engine, uint32 key, Common::SeekableReadStream
_order = 0;
_fistnum = 0;
- _frameCur = -1;
- _frameEnd = -1;
- _frameTime = 0;
- _lastRenderedFrame = -1;
_animationId = 0;
clearFistArray(_fistsUp);
@@ -95,41 +91,23 @@ FistControl::~FistControl() {
_entries.clear();
}
-void FistControl::renderFrame(uint frameNumber) {
- if ((int32)frameNumber == _lastRenderedFrame)
- return;
-
- _lastRenderedFrame = frameNumber;
-
- const Graphics::Surface *frameData;
-
- if (_animation) {
- _animation->seekToFrame(frameNumber);
- frameData = _animation->decodeNextFrame();
- if (frameData)
- _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _anmRect);
- }
-}
-
bool FistControl::process(uint32 deltaTimeInMillis) {
if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED)
return false;
- if (_frameCur >= 0 && _frameEnd >= 0)
- if (_frameCur <= _frameEnd) {
- _frameTime -= deltaTimeInMillis;
-
- if (_frameTime <= 0) {
- _frameTime = 1000.0 / _animation->getDuration().framerate();
-
- renderFrame(_frameCur);
-
- _frameCur++;
+ if (_animation && _animation->isPlaying()) {
+ if (_animation->endOfVideo()) {
+ _animation->stop();
+ _engine->getScriptManager()->setStateValue(_animationId, 2);
+ return false;
+ }
- if (_frameCur > _frameEnd)
- _engine->getScriptManager()->setStateValue(_animationId, 2);
- }
+ if (_animation->needsUpdate()) {
+ const Graphics::Surface *frameData = _animation->decodeNextFrame();
+ if (frameData)
+ _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _anmRect);
}
+ }
return false;
}
@@ -160,9 +138,12 @@ bool FistControl::onMouseUp(const Common::Point &screenSpacePos, const Common::P
for (int i = 0; i < _numEntries; i++)
if (_entries[i]._bitsStrt == oldStatus && _entries[i]._bitsEnd == _fiststatus) {
- _frameCur = _entries[i]._anmStrt;
- _frameEnd = _entries[i]._anmEnd;
- _frameTime = 0;
+ if (_animation) {
+ _animation->stop();
+ _animation->seekToFrame(_entries[i]._anmStrt);
+ _animation->setEndFrame(_entries[i]._anmEnd);
+ _animation->start();
+ }
_engine->getScriptManager()->setStateValue(_animationId, 1);
_engine->getScriptManager()->setStateValue(_soundKey, _entries[i]._sound);
diff --git a/engines/zvision/scripting/controls/fist_control.h b/engines/zvision/scripting/controls/fist_control.h
index 0a6b977ead..d7cbcb1f71 100644
--- a/engines/zvision/scripting/controls/fist_control.h
+++ b/engines/zvision/scripting/controls/fist_control.h
@@ -34,6 +34,7 @@ namespace Video {
namespace ZVision {
+// Only used in Zork Nemesis, handles the door lock puzzle with the skeletal fingers (td9e)
class FistControl : public Control {
public:
FistControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
@@ -63,10 +64,6 @@ private:
Video::VideoDecoder *_animation;
Common::Rect _anmRect;
int32 _soundKey;
- int32 _frameCur;
- int32 _frameEnd;
- int32 _frameTime;
- int32 _lastRenderedFrame;
int32 _animationId;
public:
@@ -75,7 +72,6 @@ public:
bool process(uint32 deltaTimeInMillis);
private:
- void renderFrame(uint frameNumber);
void readDescFile(const Common::String &fileName);
void clearFistArray(Common::Array< Common::Array<Common::Rect> > &arr);
uint32 readBits(const char *str);
diff --git a/engines/zvision/scripting/controls/hotmov_control.cpp b/engines/zvision/scripting/controls/hotmov_control.cpp
index e77272ec73..182447a990 100644
--- a/engines/zvision/scripting/controls/hotmov_control.cpp
+++ b/engines/zvision/scripting/controls/hotmov_control.cpp
@@ -41,10 +41,7 @@ HotMovControl::HotMovControl(ZVision *engine, uint32 key, Common::SeekableReadSt
: Control(engine, key, CONTROL_HOTMOV) {
_animation = NULL;
_cycle = 0;
- _curFrame = -1;
- _lastRenderedFrame = -1;
_frames.clear();
- _frameTime = 0;
_cyclesCount = 0;
_framesCount = 0;
@@ -78,6 +75,7 @@ HotMovControl::HotMovControl(ZVision *engine, uint32 key, Common::SeekableReadSt
sscanf(values.c_str(), "%s", filename);
values = Common::String(filename);
_animation = _engine->loadAnimation(values);
+ _animation->start();
} else if (param.matchString("venus_id", true)) {
_venusId = atoi(values.c_str());
}
@@ -95,41 +93,26 @@ HotMovControl::~HotMovControl() {
_frames.clear();
}
-void HotMovControl::renderFrame(uint frameNumber) {
- if ((int)frameNumber == _lastRenderedFrame)
- return;
-
- _lastRenderedFrame = frameNumber;
-
- const Graphics::Surface *frameData;
-
- if (_animation) {
- _animation->seekToFrame(frameNumber);
- frameData = _animation->decodeNextFrame();
- if (frameData)
- _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _rectangle);
- }
-}
-
bool HotMovControl::process(uint32 deltaTimeInMillis) {
if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED)
return false;
if (_cycle < _cyclesCount) {
- _frameTime -= deltaTimeInMillis;
+ if (_animation && _animation->endOfVideo()) {
+ _cycle++;
- if (_frameTime <= 0) {
- _curFrame++;
- if (_curFrame >= _framesCount) {
- _curFrame = 0;
- _cycle++;
- }
- if (_cycle != _cyclesCount)
- renderFrame(_curFrame);
- else
+ if (_cycle == _cyclesCount) {
_engine->getScriptManager()->setStateValue(_key, 2);
+ return false;
+ }
+
+ _animation->rewind();
+ }
- _frameTime = 1000.0 / _animation->getDuration().framerate();
+ if (_animation && _animation->needsUpdate()) {
+ const Graphics::Surface *frameData = _animation->decodeNextFrame();
+ if (frameData)
+ _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _rectangle);
}
}
@@ -140,8 +123,11 @@ bool HotMovControl::onMouseMove(const Common::Point &screenSpacePos, const Commo
if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED)
return false;
+ if (!_animation)
+ return false;
+
if (_cycle < _cyclesCount) {
- if (_frames[_curFrame].contains(backgroundImageSpacePos)) {
+ if (_frames[_animation->getCurFrame()].contains(backgroundImageSpacePos)) {
_engine->getCursorManager()->changeCursor(CursorIndex_Active);
return true;
}
@@ -154,8 +140,11 @@ bool HotMovControl::onMouseUp(const Common::Point &screenSpacePos, const Common:
if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED)
return false;
+ if (!_animation)
+ return false;
+
if (_cycle < _cyclesCount) {
- if (_frames[_curFrame].contains(backgroundImageSpacePos)) {
+ if (_frames[_animation->getCurFrame()].contains(backgroundImageSpacePos)) {
setVenus();
_engine->getScriptManager()->setStateValue(_key, 1);
return true;
diff --git a/engines/zvision/scripting/controls/hotmov_control.h b/engines/zvision/scripting/controls/hotmov_control.h
index b18d44c7a6..99d1fd0979 100644
--- a/engines/zvision/scripting/controls/hotmov_control.h
+++ b/engines/zvision/scripting/controls/hotmov_control.h
@@ -34,6 +34,7 @@ namespace Video {
namespace ZVision {
+// Only used in Zork Nemesis, handles movies where the player needs to click on something (mj7g, vw3g)
class HotMovControl : public Control {
public:
HotMovControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
@@ -41,9 +42,6 @@ public:
private:
int32 _framesCount;
- int32 _frameTime;
- int32 _curFrame;
- int32 _lastRenderedFrame;
int32 _cycle;
int32 _cyclesCount;
Video::VideoDecoder *_animation;
@@ -55,7 +53,6 @@ public:
bool process(uint32 deltaTimeInMillis);
private:
- void renderFrame(uint frameNumber);
void readHsFile(const Common::String &fileName);
};
diff --git a/engines/zvision/scripting/controls/input_control.cpp b/engines/zvision/scripting/controls/input_control.cpp
index e75cc15743..47da27fa08 100644
--- a/engines/zvision/scripting/controls/input_control.cpp
+++ b/engines/zvision/scripting/controls/input_control.cpp
@@ -46,9 +46,7 @@ InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStre
_enterPressed(false),
_readOnly(false),
_txtWidth(0),
- _animation(NULL),
- _frameDelay(0),
- _frame(-1) {
+ _animation(NULL) {
// Loop until we find the closing brace
Common::String line = stream.readLine();
_engine->getScriptManager()->trimCommentsAndWhiteSpace(&line);
@@ -96,11 +94,10 @@ InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStre
} else if (param.matchString("cursor_animation", true)) {
char fileName[25];
- sscanf(values.c_str(), "%25s %*u", fileName);
+ sscanf(values.c_str(), "%24s %*u", fileName);
_animation = _engine->loadAnimation(fileName);
- _frame = -1;
- _frameDelay = 0;
+ _animation->start();
} else if (param.matchString("focus", true)) {
_focused = true;
_engine->getScriptManager()->setFocusControlKey(_key);
@@ -199,7 +196,7 @@ bool InputControl::process(uint32 deltaTimeInMillis) {
// Blit the text using the RenderManager
Graphics::Surface txt;
- txt.create(_textRectangle.width(), _textRectangle.height(), _engine->_pixelFormat);
+ txt.create(_textRectangle.width(), _textRectangle.height(), _engine->_resourcePixelFormat);
if (!_readOnly || !_focused)
_txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringInit, txt);
@@ -212,18 +209,12 @@ bool InputControl::process(uint32 deltaTimeInMillis) {
}
if (_animation && !_readOnly && _focused) {
- bool needDraw = true;// = _textChanged;
- _frameDelay -= deltaTimeInMillis;
- if (_frameDelay <= 0) {
- _frame = (_frame + 1) % _animation->getFrameCount();
- _frameDelay = 1000.0 / _animation->getDuration().framerate();
- needDraw = true;
- }
+ if (_animation->endOfVideo())
+ _animation->rewind();
- if (needDraw) {
- _animation->seekToFrame(_frame);
+ if (_animation->needsUpdate()) {
const Graphics::Surface *srf = _animation->decodeNextFrame();
- uint32 xx = _textRectangle.left + _txtWidth;
+ int16 xx = _textRectangle.left + _txtWidth;
if (xx >= _textRectangle.left + (_textRectangle.width() - (int16)_animation->getWidth()))
xx = _textRectangle.left + _textRectangle.width() - (int16)_animation->getWidth();
_engine->getRenderManager()->blitSurfaceToBkg(*srf, xx, _textRectangle.top);
diff --git a/engines/zvision/scripting/controls/lever_control.cpp b/engines/zvision/scripting/controls/lever_control.cpp
index 8faa18357c..bef51f0e91 100644
--- a/engines/zvision/scripting/controls/lever_control.cpp
+++ b/engines/zvision/scripting/controls/lever_control.cpp
@@ -64,12 +64,12 @@ LeverControl::LeverControl(ZVision *engine, uint32 key, Common::SeekableReadStre
while (!stream.eos() && !line.contains('}')) {
if (param.matchString("descfile", true)) {
char levFileName[25];
- sscanf(values.c_str(), "%25s", levFileName);
+ sscanf(values.c_str(), "%24s", levFileName);
parseLevFile(levFileName);
} else if (param.matchString("cursor", true)) {
char cursorName[25];
- sscanf(values.c_str(), "%25s", cursorName);
+ sscanf(values.c_str(), "%24s", cursorName);
_cursor = _engine->getCursorManager()->getCursorId(Common::String(cursorName));
}
diff --git a/engines/zvision/scripting/controls/lever_control.h b/engines/zvision/scripting/controls/lever_control.h
index fdf4a649dc..8787234c51 100644
--- a/engines/zvision/scripting/controls/lever_control.h
+++ b/engines/zvision/scripting/controls/lever_control.h
@@ -34,6 +34,7 @@ namespace Video {
namespace ZVision {
+// Only used in Zork Nemesis, handles draggable levers (te2e, tm7e, tp2e, tt2e, tz2e)
class LeverControl : public Control {
public:
LeverControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
diff --git a/engines/zvision/scripting/controls/paint_control.cpp b/engines/zvision/scripting/controls/paint_control.cpp
index df06bb814e..62dde3d170 100644
--- a/engines/zvision/scripting/controls/paint_control.cpp
+++ b/engines/zvision/scripting/controls/paint_control.cpp
@@ -114,12 +114,18 @@ PaintControl::PaintControl(ZVision *engine, uint32 key, Common::SeekableReadStre
PaintControl::~PaintControl() {
// Clear the state value back to 0
//_engine->getScriptManager()->setStateValue(_key, 0);
- if (_paint)
+ if (_paint) {
+ _paint->free();
delete _paint;
- if (_brush)
+ }
+ if (_brush) {
+ _brush->free();
delete _brush;
- if (_bkg)
+ }
+ if (_bkg) {
+ _bkg->free();
delete _bkg;
+ }
}
bool PaintControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {
diff --git a/engines/zvision/scripting/controls/paint_control.h b/engines/zvision/scripting/controls/paint_control.h
index 8097290ac2..8c01f0e68a 100644
--- a/engines/zvision/scripting/controls/paint_control.h
+++ b/engines/zvision/scripting/controls/paint_control.h
@@ -32,6 +32,7 @@
namespace ZVision {
+// Only used in Zork Nemesis, handles the painting puzzle screen in Lucien's room in Irondune (ch4g)
class PaintControl : public Control {
public:
PaintControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
diff --git a/engines/zvision/scripting/controls/safe_control.cpp b/engines/zvision/scripting/controls/safe_control.cpp
index 71be692431..6ba34106d0 100644
--- a/engines/zvision/scripting/controls/safe_control.cpp
+++ b/engines/zvision/scripting/controls/safe_control.cpp
@@ -49,10 +49,7 @@ SafeControl::SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream
_outerRadiusSqr = 0;
_zeroPointer = 0;
_startPointer = 0;
- _curFrame = -1;
_targetFrame = 0;
- _frameTime = 0;
- _lastRenderedFrame = -1;
// Loop until we find the closing brace
Common::String line = stream.readLine();
@@ -64,6 +61,7 @@ SafeControl::SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream
while (!stream.eos() && !line.contains('}')) {
if (param.matchString("animation", true)) {
_animation = _engine->loadAnimation(values);
+ _animation->start();
} else if (param.matchString("rectangle", true)) {
int x;
int y;
@@ -104,7 +102,9 @@ SafeControl::SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream
_engine->getScriptManager()->trimCommentsAndWhiteSpace(&line);
getParams(line, param, values);
}
- renderFrame(_curState);
+
+ if (_animation)
+ _animation->seekToFrame(_curState);
}
SafeControl::~SafeControl() {
@@ -113,44 +113,20 @@ SafeControl::~SafeControl() {
}
-void SafeControl::renderFrame(uint frameNumber) {
- if (frameNumber == 0) {
- _lastRenderedFrame = frameNumber;
- } else if ((int16)frameNumber < _lastRenderedFrame) {
- _lastRenderedFrame = frameNumber;
- frameNumber = (_statesCount * 2) - frameNumber;
- } else {
- _lastRenderedFrame = frameNumber;
- }
-
- const Graphics::Surface *frameData;
- int x = _rectangle.left;
- int y = _rectangle.top;
-
- _animation->seekToFrame(frameNumber);
- frameData = _animation->decodeNextFrame();
- if (frameData)
- _engine->getRenderManager()->blitSurfaceToBkg(*frameData, x, y);
-}
-
bool SafeControl::process(uint32 deltaTimeInMillis) {
if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED)
return false;
- if (_curFrame != _targetFrame) {
- _frameTime -= deltaTimeInMillis;
-
- if (_frameTime <= 0) {
- if (_curFrame < _targetFrame) {
- _curFrame++;
- renderFrame(_curFrame);
- } else if (_curFrame > _targetFrame) {
- _curFrame--;
- renderFrame(_curFrame);
- }
- _frameTime = 1000.0 / _animation->getDuration().framerate();
- }
+ if (_animation && _animation->getCurFrame() != _targetFrame && _animation->needsUpdate()) {
+ // If we're past the target frame, move back one
+ if (_animation->getCurFrame() > _targetFrame)
+ _animation->seekToFrame(_animation->getCurFrame() - 1);
+
+ const Graphics::Surface *frameData = _animation->decodeNextFrame();
+ if (frameData)
+ _engine->getRenderManager()->blitSurfaceToBkg(*frameData, _rectangle.left, _rectangle.top);
}
+
return false;
}
@@ -187,7 +163,8 @@ bool SafeControl::onMouseUp(const Common::Point &screenSpacePos, const Common::P
int16 tmp2 = (m_state + _curState - _zeroPointer + _statesCount - 1) % _statesCount;
- _curFrame = (_curState + _statesCount - _startPointer) % _statesCount;
+ if (_animation)
+ _animation->seekToFrame((_curState + _statesCount - _startPointer) % _statesCount);
_curState = (_statesCount * 2 + tmp2) % _statesCount;
diff --git a/engines/zvision/scripting/controls/safe_control.h b/engines/zvision/scripting/controls/safe_control.h
index 6e1095e304..3e8c17635c 100644
--- a/engines/zvision/scripting/controls/safe_control.h
+++ b/engines/zvision/scripting/controls/safe_control.h
@@ -34,6 +34,7 @@ namespace Video {
namespace ZVision {
+// Only used in Zork Nemesis, handles the safe in the Asylum (ac4g)
class SafeControl : public Control {
public:
SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
@@ -51,19 +52,12 @@ private:
int32 _outerRadiusSqr;
int16 _zeroPointer;
int16 _startPointer;
- int16 _curFrame;
int16 _targetFrame;
- int32 _frameTime;
-
- int16 _lastRenderedFrame;
public:
bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos);
bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos);
bool process(uint32 deltaTimeInMillis);
-
-private:
- void renderFrame(uint frameNumber);
};
} // End of namespace ZVision
diff --git a/engines/zvision/scripting/controls/save_control.cpp b/engines/zvision/scripting/controls/save_control.cpp
index b35611feca..6cedddffeb 100644
--- a/engines/zvision/scripting/controls/save_control.cpp
+++ b/engines/zvision/scripting/controls/save_control.cpp
@@ -29,7 +29,8 @@
#include "zvision/scripting/script_manager.h"
#include "zvision/text/string_manager.h"
-#include "zvision/core/save_manager.h"
+#include "zvision/file/save_manager.h"
+#include "zvision/graphics/render_manager.h"
#include "common/str.h"
#include "common/stream.h"
@@ -97,18 +98,18 @@ bool SaveControl::process(uint32 deltaTimeInMillis) {
if (inp->getText().size() > 0) {
bool toSave = true;
if (iter->exist)
- if (!_engine->askQuestion(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEXIST)))
+ if (!_engine->getRenderManager()->askQuestion(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEXIST)))
toSave = false;
if (toSave) {
// FIXME: At this point, the screen shows the save control, so the save game thumbnails will always
// show the save control
_engine->getSaveManager()->saveGameBuffered(iter->saveId, inp->getText());
- _engine->delayedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVED), 2000);
+ _engine->getRenderManager()->delayedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVED), 2000);
_engine->getScriptManager()->changeLocation(_engine->getScriptManager()->getLastMenuLocation());
}
} else {
- _engine->timedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEMPTY), 2000);
+ _engine->getRenderManager()->timedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEMPTY), 2000);
}
} else {
_engine->getSaveManager()->loadGame(iter->saveId);
diff --git a/engines/zvision/scripting/controls/titler_control.cpp b/engines/zvision/scripting/controls/titler_control.cpp
index 10ba0af655..542e0a0b67 100644
--- a/engines/zvision/scripting/controls/titler_control.cpp
+++ b/engines/zvision/scripting/controls/titler_control.cpp
@@ -67,14 +67,16 @@ TitlerControl::TitlerControl(ZVision *engine, uint32 key, Common::SeekableReadSt
if (!_rectangle.isEmpty()) {
_surface = new Graphics::Surface;
- _surface->create(_rectangle.width(), _rectangle.height(), _engine->_pixelFormat);
+ _surface->create(_rectangle.width(), _rectangle.height(), _engine->_resourcePixelFormat);
_surface->fillRect(Common::Rect(_surface->w, _surface->h), 0);
}
}
TitlerControl::~TitlerControl() {
- if (_surface)
+ if (_surface) {
+ _surface->free();
delete _surface;
+ }
}
void TitlerControl::setString(int strLine) {
diff --git a/engines/zvision/scripting/controls/titler_control.h b/engines/zvision/scripting/controls/titler_control.h
index 075e47c9e9..dd96e4a846 100644
--- a/engines/zvision/scripting/controls/titler_control.h
+++ b/engines/zvision/scripting/controls/titler_control.h
@@ -32,6 +32,7 @@
namespace ZVision {
+// Only used in Zork Nemesis, handles the death screen with the Restore/Exit buttons
class TitlerControl : public Control {
public:
TitlerControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
diff --git a/engines/zvision/scripting/sidefx/animation_node.cpp b/engines/zvision/scripting/effects/animation_effect.cpp
index 3a21227d1a..511a0db353 100644
--- a/engines/zvision/scripting/sidefx/animation_node.cpp
+++ b/engines/zvision/scripting/effects/animation_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/animation_node.h"
+#include "zvision/scripting/effects/animation_effect.h"
#include "zvision/zvision.h"
#include "zvision/graphics/render_manager.h"
@@ -33,20 +33,27 @@
namespace ZVision {
-AnimationNode::AnimationNode(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool DisposeAfterUse)
- : SideFX(engine, controlKey, SIDEFX_ANIM),
- _DisposeAfterUse(DisposeAfterUse),
+AnimationEffect::AnimationEffect(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool disposeAfterUse)
+ : ScriptingEffect(engine, controlKey, SCRIPTING_EFFECT_ANIM),
+ _disposeAfterUse(disposeAfterUse),
_mask(mask),
_animation(NULL) {
_animation = engine->loadAnimation(fileName);
- _frmDelay = 1000.0 / _animation->getDuration().framerate();
- if (frate > 0)
- _frmDelay = 1000.0 / frate;
+ if (frate > 0) {
+ _frmDelayOverride = (int32)(1000.0 / frate);
+
+ // WORKAROUND: We do not allow the engine to delay more than 66 msec
+ // per frame (15fps max)
+ if (_frmDelayOverride > 66)
+ _frmDelayOverride = 66;
+ } else {
+ _frmDelayOverride = 0;
+ }
}
-AnimationNode::~AnimationNode() {
+AnimationEffect::~AnimationEffect() {
if (_animation)
delete _animation;
@@ -56,60 +63,83 @@ AnimationNode::~AnimationNode() {
if (it != _playList.end()) {
_engine->getScriptManager()->setStateValue((*it).slot, 2);
- if ((*it)._scaled)
+ if ((*it)._scaled) {
+ (*it)._scaled->free();
delete(*it)._scaled;
+ }
}
_playList.clear();
}
-bool AnimationNode::process(uint32 deltaTimeInMillis) {
+bool AnimationEffect::process(uint32 deltaTimeInMillis) {
+ ScriptManager *scriptManager = _engine->getScriptManager();
+ RenderManager *renderManager = _engine->getRenderManager();
+ RenderTable::RenderState renderState = renderManager->getRenderTable()->getRenderState();
+ bool isPanorama = (renderState == RenderTable::PANORAMA);
+ int16 velocity = _engine->getMouseVelocity() + _engine->getKeyboardVelocity();
+
+ // Do not update animation nodes in panoramic mode while turning, if the user
+ // has set this option
+ if (scriptManager->getStateValue(StateKey_NoTurnAnim) == 1 && isPanorama && velocity)
+ return false;
+
PlayNodes::iterator it = _playList.begin();
if (it != _playList.end()) {
playnode *nod = &(*it);
- nod->_delay -= deltaTimeInMillis;
- if (nod->_delay <= 0) {
- nod->_delay += _frmDelay;
-
- const Graphics::Surface *frame = NULL;
-
- if (nod->_curFrame == -1) { // Start of new playlist node
- nod->_curFrame = nod->start;
-
- _animation->seekToFrame(nod->_curFrame);
- frame = _animation->decodeNextFrame();
-
- nod->_delay = _frmDelay;
- if (nod->slot)
- _engine->getScriptManager()->setStateValue(nod->slot, 1);
- } else {
- nod->_curFrame++;
-
- if (nod->_curFrame > nod->stop) {
- nod->loop--;
-
- if (nod->loop == 0) {
- if (nod->slot >= 0)
- _engine->getScriptManager()->setStateValue(nod->slot, 2);
- if (nod->_scaled)
- delete nod->_scaled;
- _playList.erase(it);
- return _DisposeAfterUse;
- }
-
- nod->_curFrame = nod->start;
- _animation->seekToFrame(nod->_curFrame);
+ if (nod->_curFrame == -1) {
+ // The node is just beginning playback
+ nod->_curFrame = nod->start;
+
+ _animation->start();
+ _animation->seekToFrame(nod->start);
+ _animation->setEndFrame(nod->stop);
+
+ nod->_delay = deltaTimeInMillis; // Force the frame to draw
+ if (nod->slot)
+ scriptManager->setStateValue(nod->slot, 1);
+ } else if (_animation->endOfVideo()) {
+ // The node has reached the end; check if we need to loop
+ nod->loop--;
+
+ if (nod->loop == 0) {
+ if (nod->slot >= 0)
+ scriptManager->setStateValue(nod->slot, 2);
+ if (nod->_scaled) {
+ nod->_scaled->free();
+ delete nod->_scaled;
}
+ _playList.erase(it);
+ return _disposeAfterUse;
+ }
- frame = _animation->decodeNextFrame();
+ nod->_curFrame = nod->start;
+ _animation->seekToFrame(nod->start);
+ }
+
+ // Check if we need to draw a frame
+ bool needsUpdate = false;
+ if (_frmDelayOverride == 0) {
+ // If not overridden, use the VideoDecoder's check
+ needsUpdate = _animation->needsUpdate();
+ } else {
+ // Otherwise, implement our own timing
+ nod->_delay -= deltaTimeInMillis;
+
+ if (nod->_delay <= 0) {
+ nod->_delay += _frmDelayOverride;
+ needsUpdate = true;
}
+ }
- if (frame) {
+ if (needsUpdate) {
+ const Graphics::Surface *frame = _animation->decodeNextFrame();
+ if (frame) {
uint32 dstw;
uint32 dsth;
- if (_engine->getRenderManager()->getRenderTable()->getRenderState() == RenderTable::PANORAMA) {
+ if (isPanorama) {
dstw = nod->pos.height();
dsth = nod->pos.width();
} else {
@@ -126,6 +156,7 @@ bool AnimationNode::process(uint32 deltaTimeInMillis) {
if (frame->w > dstw || frame->h > dsth || (frame->w == dstw / 2 && frame->h == dsth / 2)) {
if (nod->_scaled)
if (nod->_scaled->w != dstw || nod->_scaled->h != dsth) {
+ nod->_scaled->free();
delete nod->_scaled;
nod->_scaled = NULL;
}
@@ -135,22 +166,17 @@ bool AnimationNode::process(uint32 deltaTimeInMillis) {
nod->_scaled->create(dstw, dsth, frame->format);
}
- _engine->getRenderManager()->scaleBuffer(frame->getPixels(), nod->_scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, dstw, dsth);
+ renderManager->scaleBuffer(frame->getPixels(), nod->_scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, dstw, dsth);
frame = nod->_scaled;
}
- if (_engine->getRenderManager()->getRenderTable()->getRenderState() == RenderTable::PANORAMA) {
+ if (isPanorama) {
Graphics::Surface *transposed = RenderManager::tranposeSurface(frame);
- if (_mask > 0)
- _engine->getRenderManager()->blitSurfaceToBkg(*transposed, nod->pos.left, nod->pos.top, _mask);
- else
- _engine->getRenderManager()->blitSurfaceToBkg(*transposed, nod->pos.left, nod->pos.top);
+ renderManager->blitSurfaceToBkg(*transposed, nod->pos.left, nod->pos.top, _mask);
+ transposed->free();
delete transposed;
} else {
- if (_mask > 0)
- _engine->getRenderManager()->blitSurfaceToBkg(*frame, nod->pos.left, nod->pos.top, _mask);
- else
- _engine->getRenderManager()->blitSurfaceToBkg(*frame, nod->pos.left, nod->pos.top);
+ renderManager->blitSurfaceToBkg(*frame, nod->pos.left, nod->pos.top, _mask);
}
}
}
@@ -159,16 +185,12 @@ bool AnimationNode::process(uint32 deltaTimeInMillis) {
return false;
}
-void AnimationNode::addPlayNode(int32 slot, int x, int y, int x2, int y2, int startFrame, int endFrame, int loops) {
+void AnimationEffect::addPlayNode(int32 slot, int x, int y, int x2, int y2, int startFrame, int endFrame, int loops) {
playnode nod;
nod.loop = loops;
nod.pos = Common::Rect(x, y, x2 + 1, y2 + 1);
nod.start = startFrame;
- nod.stop = endFrame;
-
- if (nod.stop >= (int)_animation->getFrameCount())
- nod.stop = _animation->getFrameCount() - 1;
-
+ nod.stop = CLIP<int>(endFrame, 0, _animation->getFrameCount() - 1);
nod.slot = slot;
nod._curFrame = -1;
nod._delay = 0;
@@ -176,12 +198,14 @@ void AnimationNode::addPlayNode(int32 slot, int x, int y, int x2, int y2, int st
_playList.push_back(nod);
}
-bool AnimationNode::stop() {
+bool AnimationEffect::stop() {
PlayNodes::iterator it = _playList.begin();
if (it != _playList.end()) {
_engine->getScriptManager()->setStateValue((*it).slot, 2);
- if ((*it)._scaled)
+ if ((*it)._scaled) {
+ (*it)._scaled->free();
delete(*it)._scaled;
+ }
}
_playList.clear();
@@ -190,21 +214,4 @@ bool AnimationNode::stop() {
return false;
}
-void AnimationNode::setNewFrameDelay(int32 newDelay) {
- if (newDelay > 0) {
- PlayNodes::iterator it = _playList.begin();
- if (it != _playList.end()) {
- playnode *nod = &(*it);
- float percent = (float)nod->_delay / (float)_frmDelay;
- nod->_delay = percent * newDelay; // Scale to new max
- }
-
- _frmDelay = newDelay;
- }
-}
-
-int32 AnimationNode::getFrameDelay() {
- return _frmDelay;
-}
-
} // End of namespace ZVision
diff --git a/engines/zvision/scripting/sidefx/animation_node.h b/engines/zvision/scripting/effects/animation_effect.h
index 3adfd91f32..fd6e24ab8b 100644
--- a/engines/zvision/scripting/sidefx/animation_node.h
+++ b/engines/zvision/scripting/effects/animation_effect.h
@@ -23,7 +23,7 @@
#ifndef ZVISION_ANIMATION_NODE_H
#define ZVISION_ANIMATION_NODE_H
-#include "zvision/scripting/sidefx.h"
+#include "zvision/scripting/scripting_effect.h"
#include "common/rect.h"
#include "common/list.h"
@@ -39,10 +39,10 @@ namespace ZVision {
class ZVision;
-class AnimationNode : public SideFX {
+class AnimationEffect : public ScriptingEffect {
public:
- AnimationNode(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool DisposeAfterUse = true);
- ~AnimationNode();
+ AnimationEffect(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool disposeAfterUse = true);
+ ~AnimationEffect();
struct playnode {
Common::Rect pos;
@@ -61,10 +61,10 @@ private:
PlayNodes _playList;
int32 _mask;
- bool _DisposeAfterUse;
+ bool _disposeAfterUse;
Video::VideoDecoder *_animation;
- int32 _frmDelay;
+ int32 _frmDelayOverride;
public:
bool process(uint32 deltaTimeInMillis);
@@ -72,9 +72,6 @@ public:
void addPlayNode(int32 slot, int x, int y, int x2, int y2, int startFrame, int endFrame, int loops = 1);
bool stop();
-
- void setNewFrameDelay(int32 newDelay);
- int32 getFrameDelay();
};
} // End of namespace ZVision
diff --git a/engines/zvision/scripting/sidefx/distort_node.cpp b/engines/zvision/scripting/effects/distort_effect.cpp
index 0d5c8b1ed5..78c4a1b9a8 100644
--- a/engines/zvision/scripting/sidefx/distort_node.cpp
+++ b/engines/zvision/scripting/effects/distort_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/distort_node.h"
+#include "zvision/scripting/effects/distort_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -34,7 +34,7 @@
namespace ZVision {
DistortNode::DistortNode(ZVision *engine, uint32 key, int16 speed, float startAngle, float endAngle, float startLineScale, float endLineScale)
- : SideFX(engine, key, SIDEFX_DISTORT) {
+ : ScriptingEffect(engine, key, SCRIPTING_EFFECT_DISTORT) {
_angle = _engine->getRenderManager()->getRenderTable()->getAngle();
_linScale = _engine->getRenderManager()->getRenderTable()->getLinscale();
@@ -65,7 +65,6 @@ DistortNode::~DistortNode() {
}
bool DistortNode::process(uint32 deltaTimeInMillis) {
-
float updTime = deltaTimeInMillis / (1000.0 / 60.0);
if (_incr)
diff --git a/engines/zvision/scripting/sidefx/distort_node.h b/engines/zvision/scripting/effects/distort_effect.h
index 787a69bdde..c64f10e6ff 100644
--- a/engines/zvision/scripting/sidefx/distort_node.h
+++ b/engines/zvision/scripting/effects/distort_effect.h
@@ -23,13 +23,13 @@
#ifndef ZVISION_DISTORT_NODE_H
#define ZVISION_DISTORT_NODE_H
-#include "zvision/scripting/sidefx.h"
+#include "zvision/scripting/scripting_effect.h"
namespace ZVision {
class ZVision;
-class DistortNode : public SideFX {
+class DistortNode : public ScriptingEffect {
public:
DistortNode(ZVision *engine, uint32 key, int16 speed, float startAngle, float endAngle, float startLineScale, float endLineScale);
~DistortNode();
diff --git a/engines/zvision/scripting/sidefx/music_node.cpp b/engines/zvision/scripting/effects/music_effect.cpp
index 56598189f6..102f330305 100644
--- a/engines/zvision/scripting/sidefx/music_node.cpp
+++ b/engines/zvision/scripting/effects/music_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/music_node.h"
+#include "zvision/scripting/effects/music_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -37,7 +37,7 @@
namespace ZVision {
MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool loop, int8 volume)
- : MusicNodeBASE(engine, key, SIDEFX_AUDIO) {
+ : MusicNodeBASE(engine, key, SCRIPTING_EFFECT_AUDIO) {
_loop = loop;
_volume = volume;
_crossfade = false;
@@ -88,7 +88,7 @@ MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool
}
MusicNode::~MusicNode() {
- if (!_loaded)
+ if (_loaded)
_engine->_mixer->stopHandle(_handle);
if (_key != StateKey_NotSet)
_engine->getScriptManager()->setStateValue(_key, 2);
@@ -137,7 +137,7 @@ bool MusicNode::process(uint32 deltaTimeInMillis) {
if (_pantrack || _volume != _newvol)
setVolume(_newvol);
- if (_sub)
+ if (_sub && _engine->getScriptManager()->getStateValue(StateKey_Subtitles) == 1)
_sub->process(_engine->_mixer->getSoundElapsedTime(_handle) / 100);
}
return false;
@@ -179,26 +179,26 @@ void MusicNode::setVolume(uint8 newVolume) {
}
PanTrackNode::PanTrackNode(ZVision *engine, uint32 key, uint32 slot, int16 pos)
- : SideFX(engine, key, SIDEFX_PANTRACK) {
+ : ScriptingEffect(engine, key, SCRIPTING_EFFECT_PANTRACK) {
_slot = slot;
- SideFX *fx = _engine->getScriptManager()->getSideFX(slot);
- if (fx && fx->getType() == SIDEFX_AUDIO) {
+ ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(slot);
+ if (fx && fx->getType() == SCRIPTING_EFFECT_AUDIO) {
MusicNodeBASE *mus = (MusicNodeBASE *)fx;
mus->setPanTrack(pos);
}
}
PanTrackNode::~PanTrackNode() {
- SideFX *fx = _engine->getScriptManager()->getSideFX(_slot);
- if (fx && fx->getType() == SIDEFX_AUDIO) {
+ ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(_slot);
+ if (fx && fx->getType() == SCRIPTING_EFFECT_AUDIO) {
MusicNodeBASE *mus = (MusicNodeBASE *)fx;
mus->unsetPanTrack();
}
}
MusicMidiNode::MusicMidiNode(ZVision *engine, uint32 key, int8 program, int8 note, int8 volume)
- : MusicNodeBASE(engine, key, SIDEFX_AUDIO) {
+ : MusicNodeBASE(engine, key, SCRIPTING_EFFECT_AUDIO) {
_volume = volume;
_prog = program;
_noteNumber = note;
diff --git a/engines/zvision/scripting/sidefx/music_node.h b/engines/zvision/scripting/effects/music_effect.h
index 09bdc3707e..31d538f668 100644
--- a/engines/zvision/scripting/sidefx/music_node.h
+++ b/engines/zvision/scripting/effects/music_effect.h
@@ -24,8 +24,8 @@
#define ZVISION_MUSIC_NODE_H
#include "audio/mixer.h"
-#include "zvision/scripting/sidefx.h"
-#include "zvision/graphics/subtitles.h"
+#include "zvision/scripting/scripting_effect.h"
+#include "zvision/text/subtitles.h"
namespace Common {
class String;
@@ -33,9 +33,9 @@ class String;
namespace ZVision {
-class MusicNodeBASE : public SideFX {
+class MusicNodeBASE : public ScriptingEffect {
public:
- MusicNodeBASE(ZVision *engine, uint32 key, SideFXType type) : SideFX(engine, key, type) {}
+ MusicNodeBASE(ZVision *engine, uint32 key, ScriptingEffectType type) : ScriptingEffect(engine, key, type) {}
~MusicNodeBASE() {}
/**
@@ -91,6 +91,7 @@ private:
bool _loaded;
};
+// Only used by Zork: Nemesis, for the flute and piano puzzles (tj4e and ve6f, as well as vr)
class MusicMidiNode : public MusicNodeBASE {
public:
MusicMidiNode(ZVision *engine, uint32 key, int8 program, int8 note, int8 volume);
@@ -120,7 +121,7 @@ private:
int8 _prog;
};
-class PanTrackNode : public SideFX {
+class PanTrackNode : public ScriptingEffect {
public:
PanTrackNode(ZVision *engine, uint32 key, uint32 slot, int16 pos);
~PanTrackNode();
diff --git a/engines/zvision/scripting/sidefx/region_node.cpp b/engines/zvision/scripting/effects/region_effect.cpp
index de613d8af2..78061cf4de 100644
--- a/engines/zvision/scripting/sidefx/region_node.cpp
+++ b/engines/zvision/scripting/effects/region_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/region_node.h"
+#include "zvision/scripting/effects/region_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -30,8 +30,8 @@
namespace ZVision {
-RegionNode::RegionNode(ZVision *engine, uint32 key, Effect *effect, uint32 delay)
- : SideFX(engine, key, SIDEFX_REGION) {
+RegionNode::RegionNode(ZVision *engine, uint32 key, GraphicsEffect *effect, uint32 delay)
+ : ScriptingEffect(engine, key, SCRIPTING_EFFECT_REGION) {
_effect = effect;
_delay = delay;
_timeLeft = 0;
diff --git a/engines/zvision/scripting/sidefx/region_node.h b/engines/zvision/scripting/effects/region_effect.h
index ec716b6e3e..4fc16224ff 100644
--- a/engines/zvision/scripting/sidefx/region_node.h
+++ b/engines/zvision/scripting/effects/region_effect.h
@@ -25,16 +25,16 @@
#include "graphics/surface.h"
-#include "zvision/scripting/sidefx.h"
-#include "zvision/graphics/effect.h"
+#include "zvision/scripting/scripting_effect.h"
+#include "zvision/graphics/graphics_effect.h"
namespace ZVision {
class ZVision;
-class RegionNode : public SideFX {
+class RegionNode : public ScriptingEffect {
public:
- RegionNode(ZVision *engine, uint32 key, Effect *effect, uint32 delay);
+ RegionNode(ZVision *engine, uint32 key, GraphicsEffect *effect, uint32 delay);
~RegionNode();
/**
@@ -49,7 +49,7 @@ public:
private:
int32 _timeLeft;
uint32 _delay;
- Effect *_effect;
+ GraphicsEffect *_effect;
};
} // End of namespace ZVision
diff --git a/engines/zvision/scripting/sidefx/syncsound_node.cpp b/engines/zvision/scripting/effects/syncsound_effect.cpp
index c1f139694b..70ba97deb8 100644
--- a/engines/zvision/scripting/sidefx/syncsound_node.cpp
+++ b/engines/zvision/scripting/effects/syncsound_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/syncsound_node.h"
+#include "zvision/scripting/effects/syncsound_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -36,7 +36,7 @@
namespace ZVision {
SyncSoundNode::SyncSoundNode(ZVision *engine, uint32 key, Common::String &filename, int32 syncto)
- : SideFX(engine, key, SIDEFX_AUDIO) {
+ : ScriptingEffect(engine, key, SCRIPTING_EFFECT_AUDIO) {
_syncto = syncto;
_sub = NULL;
@@ -76,7 +76,7 @@ bool SyncSoundNode::process(uint32 deltaTimeInMillis) {
if (_engine->getScriptManager()->getSideFX(_syncto) == NULL)
return stop();
- if (_sub)
+ if (_sub && _engine->getScriptManager()->getStateValue(StateKey_Subtitles) == 1)
_sub->process(_engine->_mixer->getSoundElapsedTime(_handle) / 100);
}
return false;
diff --git a/engines/zvision/scripting/sidefx/syncsound_node.h b/engines/zvision/scripting/effects/syncsound_effect.h
index 7cd02a8aef..0eabff77a3 100644
--- a/engines/zvision/scripting/sidefx/syncsound_node.h
+++ b/engines/zvision/scripting/effects/syncsound_effect.h
@@ -24,15 +24,15 @@
#define ZVISION_SYNCSOUND_NODE_H
#include "audio/mixer.h"
-#include "zvision/scripting/sidefx.h"
-#include "zvision/graphics/subtitles.h"
+#include "zvision/scripting/scripting_effect.h"
+#include "zvision/text/subtitles.h"
namespace Common {
class String;
}
namespace ZVision {
-class SyncSoundNode : public SideFX {
+class SyncSoundNode : public ScriptingEffect {
public:
SyncSoundNode(ZVision *engine, uint32 key, Common::String &file, int32 syncto);
~SyncSoundNode();
diff --git a/engines/zvision/scripting/sidefx/timer_node.cpp b/engines/zvision/scripting/effects/timer_effect.cpp
index 170f6e7472..778f9dec6c 100644
--- a/engines/zvision/scripting/sidefx/timer_node.cpp
+++ b/engines/zvision/scripting/effects/timer_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/timer_node.h"
+#include "zvision/scripting/effects/timer_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -32,7 +32,7 @@
namespace ZVision {
TimerNode::TimerNode(ZVision *engine, uint32 key, uint timeInSeconds)
- : SideFX(engine, key, SIDEFX_TIMER) {
+ : ScriptingEffect(engine, key, SCRIPTING_EFFECT_TIMER) {
_timeLeft = 0;
if (_engine->getGameId() == GID_NEMESIS)
diff --git a/engines/zvision/scripting/sidefx/timer_node.h b/engines/zvision/scripting/effects/timer_effect.h
index 7a26aff251..5e45d54d7d 100644
--- a/engines/zvision/scripting/sidefx/timer_node.h
+++ b/engines/zvision/scripting/effects/timer_effect.h
@@ -23,13 +23,13 @@
#ifndef ZVISION_TIMER_NODE_H
#define ZVISION_TIMER_NODE_H
-#include "zvision/scripting/sidefx.h"
+#include "zvision/scripting/scripting_effect.h"
namespace ZVision {
class ZVision;
-class TimerNode : public SideFX {
+class TimerNode : public ScriptingEffect {
public:
TimerNode(ZVision *engine, uint32 key, uint timeInSeconds);
~TimerNode();
diff --git a/engines/zvision/scripting/sidefx/ttytext_node.cpp b/engines/zvision/scripting/effects/ttytext_effect.cpp
index 9a7fa01649..c60b3aa8c5 100644
--- a/engines/zvision/scripting/sidefx/ttytext_node.cpp
+++ b/engines/zvision/scripting/effects/ttytext_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/ttytext_node.h"
+#include "zvision/scripting/effects/ttytext_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -35,7 +35,7 @@
namespace ZVision {
ttyTextNode::ttyTextNode(ZVision *engine, uint32 key, const Common::String &file, const Common::Rect &r, int32 delay) :
- SideFX(engine, key, SIDEFX_TTYTXT),
+ ScriptingEffect(engine, key, SCRIPTING_EFFECT_TTYTXT),
_fnt(engine) {
_delay = delay;
_r = r;
@@ -56,8 +56,8 @@ ttyTextNode::ttyTextNode(ZVision *engine, uint32 key, const Common::String &file
delete infile;
}
- _img.create(_r.width(), _r.height(), _engine->_pixelFormat);
- _style.sharp = true;
+ _img.create(_r.width(), _r.height(), _engine->_resourcePixelFormat);
+ _style._sharp = true;
_style.readAllStyle(_txtbuf);
_style.setFont(_fnt);
_engine->getScriptManager()->setStateValue(_key, 1);
@@ -96,7 +96,7 @@ bool ttyTextNode::process(uint32 deltaTimeInMillis) {
if (ret & TXT_RET_HASSTBOX) {
Common::String buf;
- buf = Common::String::format("%d", _engine->getScriptManager()->getStateValue(_style.statebox));
+ buf = Common::String::format("%d", _engine->getScriptManager()->getStateValue(_style._statebox));
for (uint8 j = 0; j < buf.size(); j++)
outchar(buf[j]);
@@ -158,7 +158,7 @@ void ttyTextNode::newline() {
}
void ttyTextNode::outchar(uint16 chr) {
- uint32 clr = _engine->_pixelFormat.RGBToColor(_style.red, _style.green, _style.blue);
+ uint32 clr = _engine->_resourcePixelFormat.RGBToColor(_style._red, _style._green, _style._blue);
if (_dx + _fnt.getCharWidth(chr) > _r.width())
newline();
diff --git a/engines/zvision/scripting/sidefx/ttytext_node.h b/engines/zvision/scripting/effects/ttytext_effect.h
index b6cbed3e34..8d8a2518c7 100644
--- a/engines/zvision/scripting/sidefx/ttytext_node.h
+++ b/engines/zvision/scripting/effects/ttytext_effect.h
@@ -26,16 +26,16 @@
#include "common/rect.h"
#include "graphics/surface.h"
-#include "zvision/scripting/sidefx.h"
+#include "zvision/scripting/scripting_effect.h"
#include "zvision/text/text.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
namespace Common {
class String;
}
namespace ZVision {
-class ttyTextNode : public SideFX {
+class ttyTextNode : public ScriptingEffect {
public:
ttyTextNode(ZVision *engine, uint32 key, const Common::String &file, const Common::Rect &r, int32 delay);
~ttyTextNode();
diff --git a/engines/zvision/core/menu.cpp b/engines/zvision/scripting/menu.cpp
index 31e0d71370..16aa57e3ae 100644
--- a/engines/zvision/core/menu.cpp
+++ b/engines/zvision/scripting/menu.cpp
@@ -20,26 +20,22 @@
*
*/
-#include "common/scummsys.h"
-
-#include "zvision/core/menu.h"
-
#include "zvision/graphics/render_manager.h"
+#include "zvision/scripting/menu.h"
namespace ZVision {
enum {
- SLOT_START_SLOT = 151,
- SLOT_SPELL_1 = 191,
- SLOT_USER_CHOSE_THIS_SPELL = 205,
- SLOT_REVERSED_SPELLBOOK = 206
+ kMainMenuSave = 0,
+ kMainMenuLoad = 1,
+ kMainMenuPrefs = 2,
+ kMainMenuExit = 3
};
enum {
- menu_MAIN_SAVE = 0,
- menu_MAIN_REST = 1,
- menu_MAIN_PREF = 2,
- menu_MAIN_EXIT = 3
+ kMenuItem = 0,
+ kMenuMagic = 1,
+ kMenuMain = 2
};
MenuHandler::MenuHandler(ZVision *engine) {
@@ -122,8 +118,8 @@ MenuZGI::~MenuZGI() {
void MenuZGI::onMouseUp(const Common::Point &Pos) {
if (Pos.y < 40) {
switch (menuMouseFocus) {
- case menu_ITEM:
- if (menuBarFlag & menuBar_Items) {
+ case kMenuItem:
+ if (menuBarFlag & kMenubarItems) {
int itemCount = _engine->getScriptManager()->getStateValue(StateKey_Inv_TotalSlots);
if (itemCount == 0)
itemCount = 20;
@@ -131,13 +127,13 @@ void MenuZGI::onMouseUp(const Common::Point &Pos) {
for (int i = 0; i < itemCount; i++) {
int itemspace = (600 - 28) / itemCount;
- if (Common::Rect(scrollPos[menu_ITEM] + itemspace * i, 0,
- scrollPos[menu_ITEM] + itemspace * i + 28, 32).contains(Pos)) {
+ if (Common::Rect(scrollPos[kMenuItem] + itemspace * i, 0,
+ scrollPos[kMenuItem] + itemspace * i + 28, 32).contains(Pos)) {
int32 mouseItem = _engine->getScriptManager()->getStateValue(StateKey_InventoryItem);
if (mouseItem >= 0 && mouseItem < 0xE0) {
_engine->getScriptManager()->inventoryDrop(mouseItem);
- _engine->getScriptManager()->inventoryAdd(_engine->getScriptManager()->getStateValue(SLOT_START_SLOT + i));
- _engine->getScriptManager()->setStateValue(SLOT_START_SLOT + i, mouseItem);
+ _engine->getScriptManager()->inventoryAdd(_engine->getScriptManager()->getStateValue(StateKey_Inv_StartSlot + i));
+ _engine->getScriptManager()->setStateValue(StateKey_Inv_StartSlot + i, mouseItem);
redraw = true;
}
@@ -146,62 +142,62 @@ void MenuZGI::onMouseUp(const Common::Point &Pos) {
}
break;
- case menu_MAGIC:
- if (menuBarFlag & menuBar_Magic) {
+ case kMenuMagic:
+ if (menuBarFlag & kMenubarMagic) {
for (int i = 0; i < 12; i++) {
- uint itemnum = _engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + i);
+ uint itemnum = _engine->getScriptManager()->getStateValue(StateKey_Spell_1 + i);
if (itemnum != 0) {
- if (_engine->getScriptManager()->getStateValue(SLOT_REVERSED_SPELLBOOK) == 1)
+ if (_engine->getScriptManager()->getStateValue(StateKey_Reversed_Spellbooc) == 1)
itemnum = 0xEE + i;
else
itemnum = 0xE0 + i;
}
if (itemnum)
if (_engine->getScriptManager()->getStateValue(StateKey_InventoryItem) == 0 || _engine->getScriptManager()->getStateValue(StateKey_InventoryItem) >= 0xE0)
- if (Common::Rect(668 + 47 * i - scrollPos[menu_MAGIC], 0,
- 668 + 47 * i - scrollPos[menu_MAGIC] + 28, 32).contains(Pos))
- _engine->getScriptManager()->setStateValue(SLOT_USER_CHOSE_THIS_SPELL, itemnum);
+ if (Common::Rect(668 + 47 * i - scrollPos[kMenuMagic], 0,
+ 668 + 47 * i - scrollPos[kMenuMagic] + 28, 32).contains(Pos))
+ _engine->getScriptManager()->setStateValue(StateKey_Active_Spell, itemnum);
}
}
break;
- case menu_MAIN:
+ case kMenuMain:
// Exit
- if (menuBarFlag & menuBar_Exit)
+ if (menuBarFlag & kMenubarExit)
if (Common::Rect(320 + 135,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 + 135 + 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
_engine->ifQuit();
}
// Settings
- if (menuBarFlag & menuBar_Settings)
+ if (menuBarFlag & kMenubarSettings)
if (Common::Rect(320 ,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 + 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
_engine->getScriptManager()->changeLocation('g', 'j', 'p', 'e', 0);
}
// Load
- if (menuBarFlag & menuBar_Restore)
+ if (menuBarFlag & kMenubarRestore)
if (Common::Rect(320 - 135,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
_engine->getScriptManager()->changeLocation('g', 'j', 'r', 'e', 0);
}
// Save
- if (menuBarFlag & menuBar_Save)
+ if (menuBarFlag & kMenubarSave)
if (Common::Rect(320 - 135 * 2,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 - 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
_engine->getScriptManager()->changeLocation('g', 'j', 's', 'e', 0);
}
break;
@@ -216,8 +212,8 @@ void MenuZGI::onMouseMove(const Common::Point &Pos) {
redraw = true;
inmenu = true;
switch (menuMouseFocus) {
- case menu_ITEM:
- if (menuBarFlag & menuBar_Items) {
+ case kMenuItem:
+ if (menuBarFlag & kMenubarItems) {
int itemCount = _engine->getScriptManager()->getStateValue(StateKey_Inv_TotalSlots);
if (itemCount == 0)
itemCount = 20;
@@ -231,78 +227,78 @@ void MenuZGI::onMouseMove(const Common::Point &Pos) {
for (int i = 0; i < itemCount; i++) {
int itemspace = (600 - 28) / itemCount;
- if (Common::Rect(scrollPos[menu_ITEM] + itemspace * i, 0,
- scrollPos[menu_ITEM] + itemspace * i + 28, 32).contains(Pos)) {
+ if (Common::Rect(scrollPos[kMenuItem] + itemspace * i, 0,
+ scrollPos[kMenuItem] + itemspace * i + 28, 32).contains(Pos)) {
mouseOnItem = i;
break;
}
}
if (lastItem != mouseOnItem)
- if (_engine->getScriptManager()->getStateValue(SLOT_START_SLOT + mouseOnItem) ||
- _engine->getScriptManager()->getStateValue(SLOT_START_SLOT + lastItem))
+ if (_engine->getScriptManager()->getStateValue(StateKey_Inv_StartSlot + mouseOnItem) ||
+ _engine->getScriptManager()->getStateValue(StateKey_Inv_StartSlot + lastItem))
redraw = true;
}
break;
- case menu_MAGIC:
- if (menuBarFlag & menuBar_Magic) {
+ case kMenuMagic:
+ if (menuBarFlag & kMenubarMagic) {
int lastItem = mouseOnItem;
mouseOnItem = -1;
for (int i = 0; i < 12; i++) {
- if (Common::Rect(668 + 47 * i - scrollPos[menu_MAGIC], 0,
- 668 + 47 * i - scrollPos[menu_MAGIC] + 28, 32).contains(Pos)) {
+ if (Common::Rect(668 + 47 * i - scrollPos[kMenuMagic], 0,
+ 668 + 47 * i - scrollPos[kMenuMagic] + 28, 32).contains(Pos)) {
mouseOnItem = i;
break;
}
}
if (lastItem != mouseOnItem)
- if (_engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + mouseOnItem) ||
- _engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + lastItem))
+ if (_engine->getScriptManager()->getStateValue(StateKey_Spell_1 + mouseOnItem) ||
+ _engine->getScriptManager()->getStateValue(StateKey_Spell_1 + lastItem))
redraw = true;
}
break;
- case menu_MAIN: {
+ case kMenuMain: {
int lastItem = mouseOnItem;
mouseOnItem = -1;
// Exit
- if (menuBarFlag & menuBar_Exit)
+ if (menuBarFlag & kMenubarExit)
if (Common::Rect(320 + 135,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 + 135 + 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_EXIT;
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
+ mouseOnItem = kMainMenuExit;
}
// Settings
- if (menuBarFlag & menuBar_Settings)
+ if (menuBarFlag & kMenubarSettings)
if (Common::Rect(320 ,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 + 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_PREF;
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
+ mouseOnItem = kMainMenuPrefs;
}
// Load
- if (menuBarFlag & menuBar_Restore)
+ if (menuBarFlag & kMenubarRestore)
if (Common::Rect(320 - 135,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_REST;
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
+ mouseOnItem = kMainMenuLoad;
}
// Save
- if (menuBarFlag & menuBar_Save)
+ if (menuBarFlag & kMenubarSave)
if (Common::Rect(320 - 135 * 2,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 - 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_SAVE;
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
+ mouseOnItem = kMainMenuSave;
}
if (lastItem != mouseOnItem)
@@ -313,25 +309,25 @@ void MenuZGI::onMouseMove(const Common::Point &Pos) {
default:
int cur_menu = menuMouseFocus;
if (Common::Rect(64, 0, 64 + 512, 8).contains(Pos)) { // Main
- menuMouseFocus = menu_MAIN;
- scrolled[menu_MAIN] = false;
- scrollPos[menu_MAIN] = menuback[menu_MAIN][1].h - menuback[menu_MAIN][0].h;
+ menuMouseFocus = kMenuMain;
+ scrolled[kMenuMain] = false;
+ scrollPos[kMenuMain] = menuback[kMenuMain][1].h - menuback[kMenuMain][0].h;
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 2);
}
- if (menuBarFlag & menuBar_Magic)
+ if (menuBarFlag & kMenubarMagic)
if (Common::Rect(640 - 28, 0, 640, 32).contains(Pos)) { // Magic
- menuMouseFocus = menu_MAGIC;
- scrolled[menu_MAGIC] = false;
- scrollPos[menu_MAGIC] = 28;
+ menuMouseFocus = kMenuMagic;
+ scrolled[kMenuMagic] = false;
+ scrollPos[kMenuMagic] = 28;
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 3);
}
- if (menuBarFlag & menuBar_Items)
+ if (menuBarFlag & kMenubarItems)
if (Common::Rect(0, 0, 28, 32).contains(Pos)) { // Items
- menuMouseFocus = menu_ITEM;
- scrolled[menu_ITEM] = false;
- scrollPos[menu_ITEM] = 28 - 600;
+ menuMouseFocus = kMenuItem;
+ scrolled[kMenuItem] = false;
+ scrollPos[kMenuItem] = 28 - 600;
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 1);
}
@@ -356,24 +352,24 @@ void MenuZGI::process(uint32 deltatime) {
clean = false;
}
switch (menuMouseFocus) {
- case menu_ITEM:
- if (menuBarFlag & menuBar_Items)
- if (!scrolled[menu_ITEM]) {
+ case kMenuItem:
+ if (menuBarFlag & kMenubarItems)
+ if (!scrolled[kMenuItem]) {
redraw = true;
float scrl = 600.0 * (deltatime / 1000.0);
if (scrl == 0)
scrl = 1.0;
- scrollPos [menu_ITEM] += scrl;
+ scrollPos [kMenuItem] += scrl;
- if (scrollPos[menu_ITEM] >= 0) {
- scrolled[menu_ITEM] = true;
- scrollPos [menu_ITEM] = 0;
+ if (scrollPos[kMenuItem] >= 0) {
+ scrolled[kMenuItem] = true;
+ scrollPos [kMenuItem] = 0;
}
}
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_ITEM][0], scrollPos[menu_ITEM], 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuItem][0], scrollPos[kMenuItem], 0);
int itemCount = _engine->getScriptManager()->getStateValue(StateKey_Inv_TotalSlots);
if (itemCount == 0)
@@ -389,7 +385,7 @@ void MenuZGI::process(uint32 deltatime) {
if (mouseOnItem == i)
inrect = true;
- uint curItemId = _engine->getScriptManager()->getStateValue(SLOT_START_SLOT + i);
+ uint curItemId = _engine->getScriptManager()->getStateValue(StateKey_Inv_StartSlot + i);
if (curItemId != 0) {
if (itemId[i] != curItemId) {
@@ -402,9 +398,9 @@ void MenuZGI::process(uint32 deltatime) {
}
if (inrect)
- _engine->getRenderManager()->blitSurfaceToMenu(*items[i][1], scrollPos[menu_ITEM] + itemspace * i, 0, 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(*items[i][1], scrollPos[kMenuItem] + itemspace * i, 0, 0);
else
- _engine->getRenderManager()->blitSurfaceToMenu(*items[i][0], scrollPos[menu_ITEM] + itemspace * i, 0, 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(*items[i][0], scrollPos[kMenuItem] + itemspace * i, 0, 0);
} else {
if (items[i][0]) {
@@ -425,24 +421,24 @@ void MenuZGI::process(uint32 deltatime) {
}
break;
- case menu_MAGIC:
- if (menuBarFlag & menuBar_Magic)
- if (!scrolled[menu_MAGIC]) {
+ case kMenuMagic:
+ if (menuBarFlag & kMenubarMagic)
+ if (!scrolled[kMenuMagic]) {
redraw = true;
float scrl = 600.0 * (deltatime / 1000.0);
if (scrl == 0)
scrl = 1.0;
- scrollPos [menu_MAGIC] += scrl;
+ scrollPos [kMenuMagic] += scrl;
- if (scrollPos[menu_MAGIC] >= 600) {
- scrolled[menu_MAGIC] = true;
- scrollPos [menu_MAGIC] = 600;
+ if (scrollPos[kMenuMagic] >= 600) {
+ scrolled[kMenuMagic] = true;
+ scrollPos [kMenuMagic] = 600;
}
}
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAGIC][0], 640 - scrollPos[menu_MAGIC], 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMagic][0], 640 - scrollPos[kMenuMagic], 0);
for (int i = 0; i < 12; i++) {
bool inrect = false;
@@ -450,9 +446,9 @@ void MenuZGI::process(uint32 deltatime) {
if (mouseOnItem == i)
inrect = true;
- uint curItemId = _engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + i);
+ uint curItemId = _engine->getScriptManager()->getStateValue(StateKey_Spell_1 + i);
if (curItemId) {
- if (_engine->getScriptManager()->getStateValue(SLOT_REVERSED_SPELLBOOK) == 1)
+ if (_engine->getScriptManager()->getStateValue(StateKey_Reversed_Spellbooc) == 1)
curItemId = 0xEE + i;
else
curItemId = 0xE0 + i;
@@ -469,9 +465,9 @@ void MenuZGI::process(uint32 deltatime) {
}
if (inrect)
- _engine->getRenderManager()->blitSurfaceToMenu(*magic[i][1], 668 + 47 * i - scrollPos[menu_MAGIC], 0, 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(*magic[i][1], 668 + 47 * i - scrollPos[kMenuMagic], 0, 0);
else
- _engine->getRenderManager()->blitSurfaceToMenu(*magic[i][0], 668 + 47 * i - scrollPos[menu_MAGIC], 0, 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(*magic[i][0], 668 + 47 * i - scrollPos[kMenuMagic], 0, 0);
} else {
if (magic[i][0]) {
@@ -491,47 +487,47 @@ void MenuZGI::process(uint32 deltatime) {
}
break;
- case menu_MAIN:
- if (!scrolled[menu_MAIN]) {
+ case kMenuMain:
+ if (!scrolled[kMenuMain]) {
redraw = true;
float scrl = 32.0 * 2.0 * (deltatime / 1000.0);
if (scrl == 0)
scrl = 1.0;
- scrollPos [menu_MAIN] += scrl;
+ scrollPos [kMenuMain] += scrl;
- if (scrollPos[menu_MAIN] >= 0) {
- scrolled[menu_MAIN] = true;
- scrollPos [menu_MAIN] = 0;
+ if (scrollPos[kMenuMain] >= 0) {
+ scrolled[kMenuMain] = true;
+ scrollPos [kMenuMain] = 0;
}
}
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAIN][0], 30, scrollPos[menu_MAIN]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMain][0], 30, scrollPos[kMenuMain]);
- if (menuBarFlag & menuBar_Exit) {
- if (mouseOnItem == menu_MAIN_EXIT)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_EXIT][1], 320 + 135, scrollPos[menu_MAIN]);
+ if (menuBarFlag & kMenubarExit) {
+ if (mouseOnItem == kMainMenuExit)
+ _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuExit][1], 320 + 135, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_EXIT][0], 320 + 135, scrollPos[menu_MAIN]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuExit][0], 320 + 135, scrollPos[kMenuMain]);
}
- if (menuBarFlag & menuBar_Settings) {
- if (mouseOnItem == menu_MAIN_PREF)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_PREF][1], 320, scrollPos[menu_MAIN]);
+ if (menuBarFlag & kMenubarSettings) {
+ if (mouseOnItem == kMainMenuPrefs)
+ _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuPrefs][1], 320, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_PREF][0], 320, scrollPos[menu_MAIN]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuPrefs][0], 320, scrollPos[kMenuMain]);
}
- if (menuBarFlag & menuBar_Restore) {
- if (mouseOnItem == menu_MAIN_REST)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_REST][1], 320 - 135, scrollPos[menu_MAIN]);
+ if (menuBarFlag & kMenubarRestore) {
+ if (mouseOnItem == kMainMenuLoad)
+ _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuLoad][1], 320 - 135, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_REST][0], 320 - 135, scrollPos[menu_MAIN]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuLoad][0], 320 - 135, scrollPos[kMenuMain]);
}
- if (menuBarFlag & menuBar_Save) {
- if (mouseOnItem == menu_MAIN_SAVE)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_SAVE][1], 320 - 135 * 2, scrollPos[menu_MAIN]);
+ if (menuBarFlag & kMenubarSave) {
+ if (mouseOnItem == kMainMenuSave)
+ _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuSave][1], 320 - 135 * 2, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_SAVE][0], 320 - 135 * 2, scrollPos[menu_MAIN]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuSave][0], 320 - 135 * 2, scrollPos[kMenuMain]);
}
redraw = false;
}
@@ -539,13 +535,13 @@ void MenuZGI::process(uint32 deltatime) {
default:
if (redraw) {
if (inmenu) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAIN][1], 30, 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMain][1], 30, 0);
- if (menuBarFlag & menuBar_Items)
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_ITEM][1], 0, 0);
+ if (menuBarFlag & kMenubarItems)
+ _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuItem][1], 0, 0);
- if (menuBarFlag & menuBar_Magic)
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAGIC][1], 640 - 28, 0);
+ if (menuBarFlag & kMenubarMagic)
+ _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMagic][1], 640 - 28, 0);
}
redraw = false;
}
@@ -587,7 +583,7 @@ static const int16 buts[4][2] = { {120 , 64}, {144, 184}, {128, 328}, {120, 456}
void MenuNemesis::onMouseUp(const Common::Point &Pos) {
if (Pos.y < 40) {
// Exit
- if (menuBarFlag & menuBar_Exit)
+ if (menuBarFlag & kMenubarExit)
if (Common::Rect(buts[3][1],
scrollPos,
buts[3][0] + buts[3][1],
@@ -598,7 +594,7 @@ void MenuNemesis::onMouseUp(const Common::Point &Pos) {
}
// Settings
- if (menuBarFlag & menuBar_Settings)
+ if (menuBarFlag & kMenubarSettings)
if (Common::Rect(buts[2][1],
scrollPos,
buts[2][0] + buts[2][1],
@@ -609,7 +605,7 @@ void MenuNemesis::onMouseUp(const Common::Point &Pos) {
}
// Load
- if (menuBarFlag & menuBar_Restore)
+ if (menuBarFlag & kMenubarRestore)
if (Common::Rect(buts[1][1],
scrollPos,
buts[1][0] + buts[1][1],
@@ -620,7 +616,7 @@ void MenuNemesis::onMouseUp(const Common::Point &Pos) {
}
// Save
- if (menuBarFlag & menuBar_Save)
+ if (menuBarFlag & kMenubarSave)
if (Common::Rect(buts[0][1],
scrollPos,
buts[0][0] + buts[0][1],
@@ -644,39 +640,39 @@ void MenuNemesis::onMouseMove(const Common::Point &Pos) {
mouseOnItem = -1;
// Exit
- if (menuBarFlag & menuBar_Exit)
+ if (menuBarFlag & kMenubarExit)
if (Common::Rect(buts[3][1],
scrollPos,
buts[3][0] + buts[3][1],
scrollPos + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_EXIT;
+ mouseOnItem = kMainMenuExit;
}
// Settings
- if (menuBarFlag & menuBar_Settings)
+ if (menuBarFlag & kMenubarSettings)
if (Common::Rect(buts[2][1],
scrollPos,
buts[2][0] + buts[2][1],
scrollPos + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_PREF;
+ mouseOnItem = kMainMenuPrefs;
}
// Load
- if (menuBarFlag & menuBar_Restore)
+ if (menuBarFlag & kMenubarRestore)
if (Common::Rect(buts[1][1],
scrollPos,
buts[1][0] + buts[1][1],
scrollPos + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_REST;
+ mouseOnItem = kMainMenuLoad;
}
// Save
- if (menuBarFlag & menuBar_Save)
+ if (menuBarFlag & kMenubarSave)
if (Common::Rect(buts[0][1],
scrollPos,
buts[0][0] + buts[0][1],
scrollPos + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_SAVE;
+ mouseOnItem = kMainMenuSave;
}
if (lastItem != mouseOnItem) {
@@ -721,20 +717,20 @@ void MenuNemesis::process(uint32 deltatime) {
if (redraw) {
_engine->getRenderManager()->blitSurfaceToMenu(menubar, 64, scrollPos);
- if (menuBarFlag & menuBar_Exit)
- if (mouseOnItem == menu_MAIN_EXIT)
+ if (menuBarFlag & kMenubarExit)
+ if (mouseOnItem == kMainMenuExit)
_engine->getRenderManager()->blitSurfaceToMenu(but[3][frm], buts[3][1], scrollPos);
- if (menuBarFlag & menuBar_Settings)
- if (mouseOnItem == menu_MAIN_PREF)
+ if (menuBarFlag & kMenubarSettings)
+ if (mouseOnItem == kMainMenuPrefs)
_engine->getRenderManager()->blitSurfaceToMenu(but[2][frm], buts[2][1], scrollPos);
- if (menuBarFlag & menuBar_Restore)
- if (mouseOnItem == menu_MAIN_REST)
+ if (menuBarFlag & kMenubarRestore)
+ if (mouseOnItem == kMainMenuLoad)
_engine->getRenderManager()->blitSurfaceToMenu(but[1][frm], buts[1][1], scrollPos);
- if (menuBarFlag & menuBar_Save)
- if (mouseOnItem == menu_MAIN_SAVE)
+ if (menuBarFlag & kMenubarSave)
+ if (mouseOnItem == kMainMenuSave)
_engine->getRenderManager()->blitSurfaceToMenu(but[0][frm], buts[0][1], scrollPos);
redraw = false;
diff --git a/engines/zvision/core/menu.h b/engines/zvision/scripting/menu.h
index ebe0bb50ac..a88587966f 100644
--- a/engines/zvision/core/menu.h
+++ b/engines/zvision/scripting/menu.h
@@ -32,12 +32,12 @@
namespace ZVision {
enum menuBar {
- menuBar_Exit = 0x1,
- menuBar_Settings = 0x2,
- menuBar_Restore = 0x4,
- menuBar_Save = 0x8,
- menuBar_Items = 0x100,
- menuBar_Magic = 0x200
+ kMenubarExit = 0x1,
+ kMenubarSettings = 0x2,
+ kMenubarRestore = 0x4,
+ kMenubarSave = 0x8,
+ kMenubarItems = 0x100,
+ kMenubarMagic = 0x200
};
class MenuHandler {
@@ -84,12 +84,6 @@ private:
bool scrolled[3];
int16 scrollPos[3];
- enum {
- menu_ITEM = 0,
- menu_MAGIC = 1,
- menu_MAIN = 2
- };
-
bool clean;
bool redraw;
diff --git a/engines/zvision/scripting/scr_file_handling.cpp b/engines/zvision/scripting/scr_file_handling.cpp
index c117da5ec2..227c43557c 100644
--- a/engines/zvision/scripting/scr_file_handling.cpp
+++ b/engines/zvision/scripting/scr_file_handling.cpp
@@ -216,6 +216,7 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis
} else if (act.matchString("animpreload", true)) {
actionList.push_back(new ActionPreloadAnimation(_engine, slot, args));
} else if (act.matchString("animunload", true)) {
+ // Only used by ZGI (locations cd6e, cd6k, dg2f, dg4e, dv1j)
actionList.push_back(new ActionUnloadAnimation(_engine, slot, args));
} else if (act.matchString("attenuate", true)) {
actionList.push_back(new ActionAttenuate(_engine, slot, args));
@@ -234,12 +235,13 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis
} else if (act.matchString("disable_control", true)) {
actionList.push_back(new ActionDisableControl(_engine, slot, args));
} else if (act.matchString("disable_venus", true)) {
- actionList.push_back(new ActionDisableVenus(_engine, slot, args));
+ // Not used. Purposely left empty
} else if (act.matchString("display_message", true)) {
actionList.push_back(new ActionDisplayMessage(_engine, slot, args));
} else if (act.matchString("dissolve", true)) {
actionList.push_back(new ActionDissolve(_engine));
} else if (act.matchString("distort", true)) {
+ // Only used by Zork: Nemesis for the "treatment" puzzle in the Sanitarium (aj30)
actionList.push_back(new ActionDistort(_engine, slot, args));
} else if (act.matchString("enable_control", true)) {
actionList.push_back(new ActionEnableControl(_engine, slot, args));
@@ -248,6 +250,7 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis
} else if (act.matchString("inventory", true)) {
actionList.push_back(new ActionInventory(_engine, slot, args));
} else if (act.matchString("kill", true)) {
+ // Only used by ZGI
actionList.push_back(new ActionKill(_engine, slot, args));
} else if (act.matchString("menu_bar_enable", true)) {
actionList.push_back(new ActionMenuBarEnable(_engine, slot, args));
@@ -264,6 +267,7 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis
} else if (act.matchString("random", true)) {
actionList.push_back(new ActionRandom(_engine, slot, args));
} else if (act.matchString("region", true)) {
+ // Only used by Zork: Nemesis
actionList.push_back(new ActionRegion(_engine, slot, args));
} else if (act.matchString("restore_game", true)) {
actionList.push_back(new ActionRestoreGame(_engine, slot, args));
@@ -276,7 +280,7 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis
} else if (act.matchString("set_screen", true)) {
actionList.push_back(new ActionSetScreen(_engine, slot, args));
} else if (act.matchString("set_venus", true)) {
- actionList.push_back(new ActionSetVenus(_engine, slot, args));
+ // Not used. Purposely left empty
} else if (act.matchString("stop", true)) {
actionList.push_back(new ActionStop(_engine, slot, args));
} else if (act.matchString("streamvideo", true)) {
@@ -345,25 +349,32 @@ Control *ScriptManager::parseControl(Common::String &line, Common::SeekableReadS
Control::parsePanoramaControl(_engine, stream);
return NULL;
} else if (controlType.equalsIgnoreCase("tilt")) {
+ // Only used in Zork Nemesis, handles tilt controls (ZGI doesn't have a tilt view)
Control::parseTiltControl(_engine, stream);
return NULL;
- } else if (controlType.equalsIgnoreCase("lever")) {
- return new LeverControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("slot")) {
return new SlotControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("input")) {
return new InputControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("save")) {
return new SaveControl(_engine, key, stream);
+ } else if (controlType.equalsIgnoreCase("lever")) {
+ // Only used in Zork Nemesis, handles draggable levers (te2e, tm7e, tp2e, tt2e, tz2e)
+ return new LeverControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("safe")) {
+ // Only used in Zork Nemesis, handles the safe in the Asylum (ac4g)
return new SafeControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("hotmovie")) {
+ // Only used in Zork Nemesis, handles movies where the player needs to click on something (mj7g, vw3g)
return new HotMovControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("fist")) {
+ // Only used in Zork Nemesis, handles the door lock puzzle with the skeletal fingers (td9e)
return new FistControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("paint")) {
+ // Only used in Zork Nemesis, handles the painting puzzle screen in Lucien's room in Irondune (ch4g)
return new PaintControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("titler")) {
+ // Only used in Zork Nemesis, handles the death screen with the Restore/Exit buttons (cjde)
return new TitlerControl(_engine, key, stream);
}
return NULL;
diff --git a/engines/zvision/scripting/script_manager.cpp b/engines/zvision/scripting/script_manager.cpp
index 4c1e69072d..464e8bfe4d 100644
--- a/engines/zvision/scripting/script_manager.cpp
+++ b/engines/zvision/scripting/script_manager.cpp
@@ -27,9 +27,10 @@
#include "zvision/zvision.h"
#include "zvision/graphics/render_manager.h"
#include "zvision/graphics/cursors/cursor_manager.h"
-#include "zvision/core/save_manager.h"
+#include "zvision/file/save_manager.h"
#include "zvision/scripting/actions.h"
-#include "zvision/scripting/sidefx/timer_node.h"
+#include "zvision/scripting/menu.h"
+#include "zvision/scripting/effects/timer_effect.h"
#include "common/algorithm.h"
#include "common/hashmap.h"
@@ -381,11 +382,11 @@ void ScriptManager::setFocusControlKey(uint32 key) {
_currentlyFocusedControl = key;
}
-void ScriptManager::addSideFX(SideFX *fx) {
+void ScriptManager::addSideFX(ScriptingEffect *fx) {
_activeSideFx.push_back(fx);
}
-SideFX *ScriptManager::getSideFX(uint32 key) {
+ScriptingEffect *ScriptManager::getSideFX(uint32 key) {
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) {
if ((*iter)->getKey() == key) {
return (*iter);
@@ -429,7 +430,7 @@ void ScriptManager::killSideFx(uint32 key) {
}
}
-void ScriptManager::killSideFxType(SideFX::SideFXType type) {
+void ScriptManager::killSideFxType(ScriptingEffect::ScriptingEffectType type) {
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end();) {
if ((*iter)->getType() & type) {
(*iter)->kill();
@@ -568,10 +569,6 @@ void ScriptManager::ChangeLocationReal() {
} else {
if (_currentLocation.world == 'g' && _currentLocation.room == 'j')
_engine->getSaveManager()->flushSaveBuffer();
- else {
- // Auto save
- //_engine->getSaveManager()->autoSave();
- }
}
setStateValue(StateKey_World, _nextLocation.world);
@@ -583,7 +580,7 @@ void ScriptManager::ChangeLocationReal() {
_referenceTable.clear();
addPuzzlesToReferenceTable(universe);
- _engine->menuBarEnable(0xFFFF);
+ _engine->getMenuHandler()->setEnable(0xFFFF);
if (_nextLocation.world != _currentLocation.world) {
cleanScriptScope(nodeview);
@@ -652,7 +649,7 @@ void ScriptManager::ChangeLocationReal() {
execScope(nodeview);
}
- _engine->checkBorders();
+ _engine->getRenderManager()->checkBorders();
}
void ScriptManager::serialize(Common::WriteStream *stream) {
diff --git a/engines/zvision/scripting/script_manager.h b/engines/zvision/scripting/script_manager.h
index 1e308faf0d..78c1b77dea 100644
--- a/engines/zvision/scripting/script_manager.h
+++ b/engines/zvision/scripting/script_manager.h
@@ -25,7 +25,7 @@
#include "zvision/scripting/puzzle.h"
#include "zvision/scripting/control.h"
-#include "zvision/scripting/sidefx.h"
+#include "zvision/scripting/scripting_effect.h"
#include "common/hashmap.h"
#include "common/queue.h"
@@ -94,7 +94,12 @@ enum StateKey {
StateKey_Inv_Cnt_Slot = 100,
StateKey_Inv_1_Slot = 101,
StateKey_Inv_49_Slot = 149,
- StateKey_Inv_TotalSlots = 150
+ // ZGI only
+ StateKey_Inv_TotalSlots = 150,
+ StateKey_Inv_StartSlot = 151,
+ StateKey_Spell_1 = 191,
+ StateKey_Active_Spell = 205,
+ StateKey_Reversed_Spellbooc = 206
};
struct Location {
@@ -111,7 +116,7 @@ typedef Common::List<Puzzle *> PuzzleList;
typedef Common::Queue<Puzzle *> PuzzleQueue;
typedef Common::List<Control *> ControlList;
typedef Common::HashMap<uint32, int32> StateMap;
-typedef Common::List<SideFX *> SideFXList;
+typedef Common::List<ScriptingEffect *> SideFXList;
typedef Common::List<Common::Event> EventList;
class ScriptManager {
@@ -191,12 +196,12 @@ public:
// Only change focus control without call focus/unfocus.
void setFocusControlKey(uint32 key);
- void addSideFX(SideFX *fx);
- SideFX *getSideFX(uint32 key);
+ void addSideFX(ScriptingEffect *fx);
+ ScriptingEffect *getSideFX(uint32 key);
void deleteSideFx(uint32 key);
void stopSideFx(uint32 key);
void killSideFx(uint32 key);
- void killSideFxType(SideFX::SideFXType type);
+ void killSideFxType(ScriptingEffect::ScriptingEffectType type);
void addEvent(Common::Event);
void flushEvent(Common::EventType type);
@@ -282,7 +287,7 @@ public:
void inventoryDrop(int16 item);
void inventoryCycle();
- // TODO: Make this private. It was only made public so Console::cmdParseAllScrFiles() could use it
+private:
/**
* Parses a script file into triggers and events
*
@@ -291,7 +296,6 @@ public:
*/
void parseScrFile(const Common::String &fileName, ScriptScope &scope);
-private:
/**
* Parses the stream into a Puzzle object
* Helper method for parseScrFile.
diff --git a/engines/zvision/scripting/sidefx.h b/engines/zvision/scripting/scripting_effect.h
index 5bb14f0cdd..0af1d9c21c 100644
--- a/engines/zvision/scripting/sidefx.h
+++ b/engines/zvision/scripting/scripting_effect.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SIDEFX_H_INCLUDED
-#define SIDEFX_H_INCLUDED
+#ifndef SCRIPTING_EFFECT_H_INCLUDED
+#define SCRIPTING_EFFECT_H_INCLUDED
namespace Common {
class SeekableReadStream;
@@ -33,29 +33,39 @@ namespace ZVision {
class ZVision;
-class SideFX {
+/**
+ * The base class that represents effects created from Actions.
+ * This class is virtual.
+ *
+ * Detailed Description:
+ * A scene has Controls. By interacting with the controls, the user
+ * causes Actions to execute. Certain Actions create 'effects', for
+ * example, a sound or an animation. This is the base class for
+ * those effects.
+ */
+class ScriptingEffect {
public:
- enum SideFXType {
- SIDEFX_ANIM = 1,
- SIDEFX_AUDIO = 2,
- SIDEFX_DISTORT = 4,
- SIDEFX_PANTRACK = 8,
- SIDEFX_REGION = 16,
- SIDEFX_TIMER = 32,
- SIDEFX_TTYTXT = 64,
- SIDEFX_UNK = 128,
- SIDEFX_ALL = 255
+ enum ScriptingEffectType {
+ SCRIPTING_EFFECT_ANIM = 1,
+ SCRIPTING_EFFECT_AUDIO = 2,
+ SCRIPTING_EFFECT_DISTORT = 4,
+ SCRIPTING_EFFECT_PANTRACK = 8,
+ SCRIPTING_EFFECT_REGION = 16,
+ SCRIPTING_EFFECT_TIMER = 32,
+ SCRIPTING_EFFECT_TTYTXT = 64,
+ SCRIPTING_EFFECT_UNKNOWN = 128,
+ SCRIPTING_EFFECT_ALL = 255
};
- SideFX() : _engine(0), _key(0), _type(SIDEFX_UNK) {}
- SideFX(ZVision *engine, uint32 key, SideFXType type) : _engine(engine), _key(key), _type(type) {}
- virtual ~SideFX() {}
+ ScriptingEffect() : _engine(0), _key(0), _type(SCRIPTING_EFFECT_UNKNOWN) {}
+ ScriptingEffect(ZVision *engine, uint32 key, ScriptingEffectType type) : _engine(engine), _key(key), _type(type) {}
+ virtual ~ScriptingEffect() {}
uint32 getKey() {
return _key;
}
- SideFXType getType() {
+ ScriptingEffectType getType() {
return _type;
}
@@ -103,7 +113,7 @@ public:
protected:
ZVision *_engine;
uint32 _key;
- SideFXType _type;
+ ScriptingEffectType _type;
// Static member functions
public:
@@ -111,4 +121,4 @@ public:
};
} // End of namespace ZVision
-#endif // SIDEFX_H_INCLUDED
+#endif // SCRIPTING_EFFECT_H_INCLUDED
diff --git a/engines/zvision/sound/zork_raw.cpp b/engines/zvision/sound/zork_raw.cpp
index 8688039325..6d1980b1af 100644
--- a/engines/zvision/sound/zork_raw.cpp
+++ b/engines/zvision/sound/zork_raw.cpp
@@ -73,10 +73,7 @@ RawChunkStream::RawChunk RawChunkStream::readNextChunk(Common::SeekableReadStrea
tmp.size = 0;
tmp.data = NULL;
- if (!stream)
- return tmp;
-
- if (stream && (stream->size() == 0 || stream->eos()))
+ if (!stream || stream->size() == 0 || stream->eos())
return tmp;
tmp.size = (stream->size() - stream->pos()) * 2;
@@ -216,7 +213,6 @@ RawZorkStream::RawZorkStream(uint32 rate, bool stereo, DisposeAfterUse::Flag dis
}
int RawZorkStream::readBuffer(int16 *buffer, const int numSamples) {
-
int32 bytesRead = _streamReader.readBuffer(buffer, _stream.get(), numSamples);
if (_stream->eos())
@@ -244,16 +240,10 @@ Audio::RewindableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stre
return new RawZorkStream(rate, stereo, disposeAfterUse, stream);
}
-Audio::RewindableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size,
- int rate,
- bool stereo,
- DisposeAfterUse::Flag disposeAfterUse) {
- return makeRawZorkStream(new Common::MemoryReadStream(buffer, size, disposeAfterUse), rate, stereo, DisposeAfterUse::YES);
-}
-
Audio::RewindableAudioStream *makeRawZorkStream(const Common::String &filePath, ZVision *engine) {
Common::File *file = new Common::File();
- assert(engine->getSearchManager()->openFile(*file, filePath));
+ if (!engine->getSearchManager()->openFile(*file, filePath))
+ error("File not found: %s", filePath.c_str());
// Get the file name
Common::StringTokenizer tokenizer(filePath, "/\\");
diff --git a/engines/zvision/sound/zork_raw.h b/engines/zvision/sound/zork_raw.h
index 0b408d818c..892bad4d5f 100644
--- a/engines/zvision/sound/zork_raw.h
+++ b/engines/zvision/sound/zork_raw.h
@@ -123,20 +123,6 @@ public:
};
/**
- * Creates an audio stream, which plays from the given buffer.
- *
- * @param buffer Buffer to play from.
- * @param size Size of the buffer in bytes.
- * @param rate Rate of the sound data.
- * @param dispose AfterUse Whether to free the buffer after use (with free!).
- * @return The new SeekableAudioStream (or 0 on failure).
- */
-Audio::RewindableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size,
- int rate,
- bool stereo,
- DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
-
-/**
* Creates an audio stream, which plays from the given stream.
*
* @param stream Stream object to play from.
diff --git a/engines/zvision/text/string_manager.cpp b/engines/zvision/text/string_manager.cpp
index ec10b6220c..6b870d0b8d 100644
--- a/engines/zvision/text/string_manager.cpp
+++ b/engines/zvision/text/string_manager.cpp
@@ -43,21 +43,18 @@ StringManager::~StringManager() {
}
void StringManager::initialize(ZVisionGameId gameId) {
- if (gameId == GID_NEMESIS) {
- // TODO: Check this hardcoded filename against all versions of Nemesis
+ if (gameId == GID_NEMESIS)
loadStrFile("nemesis.str");
- } else if (gameId == GID_GRANDINQUISITOR) {
- // TODO: Check this hardcoded filename against all versions of Grand Inquisitor
+ else if (gameId == GID_GRANDINQUISITOR)
loadStrFile("inquis.str");
- }
}
void StringManager::loadStrFile(const Common::String &fileName) {
Common::File file;
if (!_engine->getSearchManager()->openFile(file, fileName)) {
- warning("%s does not exist. String parsing failed", fileName.c_str());
- return;
+ error("%s does not exist. String parsing failed", fileName.c_str());
}
+
uint lineNumber = 0;
while (!file.eos()) {
_lines[lineNumber] = readWideLine(file);
diff --git a/engines/zvision/text/string_manager.h b/engines/zvision/text/string_manager.h
index b77ad65040..f4564ee1ec 100644
--- a/engines/zvision/text/string_manager.h
+++ b/engines/zvision/text/string_manager.h
@@ -24,7 +24,7 @@
#define ZVISION_STRING_MANAGER_H
#include "zvision/detection.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
namespace Graphics {
class FontManager;
diff --git a/engines/zvision/graphics/subtitles.cpp b/engines/zvision/text/subtitles.cpp
index d2c56f0991..acf4c37c2f 100644
--- a/engines/zvision/graphics/subtitles.cpp
+++ b/engines/zvision/text/subtitles.cpp
@@ -21,7 +21,7 @@
*/
#include "zvision/graphics/render_manager.h"
-#include "zvision/graphics/subtitles.h"
+#include "zvision/text/subtitles.h"
#include "zvision/file/search_manager.h"
#include "zvision/text/text.h"
diff --git a/engines/zvision/graphics/subtitles.h b/engines/zvision/text/subtitles.h
index c3da6583a4..c3da6583a4 100644
--- a/engines/zvision/graphics/subtitles.h
+++ b/engines/zvision/text/subtitles.h
diff --git a/engines/zvision/text/text.cpp b/engines/zvision/text/text.cpp
index 406c36e5b0..a5ed044424 100644
--- a/engines/zvision/text/text.cpp
+++ b/engines/zvision/text/text.cpp
@@ -33,27 +33,31 @@
#include "zvision/text/text.h"
#include "zvision/graphics/render_manager.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
#include "zvision/scripting/script_manager.h"
namespace ZVision {
cTxtStyle::cTxtStyle() {
- fontname = "Arial";
- blue = 255;
- green = 255;
- red = 255;
- bold = false;
- escapement = 0;
- italic = false;
- justify = TXT_JUSTIFY_LEFT;
- newline = false;
- size = 12;
- skipcolor = false;
- strikeout = false;
- underline = false;
- statebox = 0;
- sharp = false;
+ _fontname = "Arial";
+ _blue = 255;
+ _green = 255;
+ _red = 255;
+ _bold = false;
+#if 0
+ _newline = false;
+ _escapement = 0;
+#endif
+ _italic = false;
+ _justify = TXT_JUSTIFY_LEFT;
+ _size = 12;
+#if 0
+ _skipcolor = false;
+#endif
+ _strikeout = false;
+ _underline = false;
+ _statebox = 0;
+ _sharp = false;
}
txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
@@ -80,10 +84,10 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (_tmp.lastChar() == '"')
_tmp.deleteLastChar();
- fontname = _tmp;
+ _fontname = _tmp;
} else {
if (!tokenizer.empty())
- fontname = token;
+ _fontname = token;
}
retval |= TXT_RET_FNTCHG;
@@ -91,8 +95,8 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
int32 tmp = atoi(token.c_str());
- if (blue != tmp) {
- blue = tmp;
+ if (_blue != tmp) {
+ _blue = tmp;
retval |= TXT_RET_FNTSTL;
}
}
@@ -100,8 +104,8 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
int32 tmp = atoi(token.c_str());
- if (red != tmp) {
- red = tmp;
+ if (_red != tmp) {
+ _red = tmp;
retval |= TXT_RET_FNTSTL;
}
}
@@ -109,43 +113,47 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
int32 tmp = atoi(token.c_str());
- if (green != tmp) {
- green = tmp;
+ if (_green != tmp) {
+ _green = tmp;
retval |= TXT_RET_FNTSTL;
}
}
} else if (token.matchString("newline", true)) {
+#if 0
if ((retval & TXT_RET_NEWLN) == 0)
- newline = 0;
+ _newline = 0;
- newline++;
+ _newline++;
+#endif
retval |= TXT_RET_NEWLN;
} else if (token.matchString("point", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
int32 tmp = atoi(token.c_str());
- if (size != tmp) {
- size = tmp;
+ if (_size != tmp) {
+ _size = tmp;
retval |= TXT_RET_FNTCHG;
}
}
} else if (token.matchString("escapement", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
+#if 0
int32 tmp = atoi(token.c_str());
- escapement = tmp;
+ _escapement = tmp;
+#endif
}
} else if (token.matchString("italic", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
if (token.matchString("on", true)) {
- if (italic != true) {
- italic = true;
+ if (_italic != true) {
+ _italic = true;
retval |= TXT_RET_FNTSTL;
}
} else if (token.matchString("off", true)) {
- if (italic != false) {
- italic = false;
+ if (_italic != false) {
+ _italic = false;
retval |= TXT_RET_FNTSTL;
}
}
@@ -154,13 +162,13 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
if (token.matchString("on", true)) {
- if (underline != true) {
- underline = true;
+ if (_underline != true) {
+ _underline = true;
retval |= TXT_RET_FNTSTL;
}
} else if (token.matchString("off", true)) {
- if (underline != false) {
- underline = false;
+ if (_underline != false) {
+ _underline = false;
retval |= TXT_RET_FNTSTL;
}
}
@@ -169,13 +177,13 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
if (token.matchString("on", true)) {
- if (strikeout != true) {
- strikeout = true;
+ if (_strikeout != true) {
+ _strikeout = true;
retval |= TXT_RET_FNTSTL;
}
} else if (token.matchString("off", true)) {
- if (strikeout != false) {
- strikeout = false;
+ if (_strikeout != false) {
+ _strikeout = false;
retval |= TXT_RET_FNTSTL;
}
}
@@ -184,13 +192,13 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
if (token.matchString("on", true)) {
- if (bold != true) {
- bold = true;
+ if (_bold != true) {
+ _bold = true;
retval |= TXT_RET_FNTSTL;
}
} else if (token.matchString("off", true)) {
- if (bold != false) {
- bold = false;
+ if (_bold != false) {
+ _bold = false;
retval |= TXT_RET_FNTSTL;
}
}
@@ -198,29 +206,31 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
} else if (token.matchString("skipcolor", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
+#if 0
if (token.matchString("on", true)) {
- skipcolor = true;
+ _skipcolor = true;
} else if (token.matchString("off", true)) {
- skipcolor = false;
+ _skipcolor = false;
}
+#endif
}
} else if (token.matchString("image", true)) {
// Not used
} else if (token.matchString("statebox", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
- statebox = atoi(token.c_str());
+ _statebox = atoi(token.c_str());
retval |= TXT_RET_HASSTBOX;
}
} else if (token.matchString("justify", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
if (token.matchString("center", true))
- justify = TXT_JUSTIFY_CENTER;
+ _justify = TXT_JUSTIFY_CENTER;
else if (token.matchString("left", true))
- justify = TXT_JUSTIFY_LEFT;
+ _justify = TXT_JUSTIFY_LEFT;
else if (token.matchString("right", true))
- justify = TXT_JUSTIFY_RIGHT;
+ _justify = TXT_JUSTIFY_RIGHT;
}
}
}
@@ -247,19 +257,19 @@ void cTxtStyle::readAllStyle(const Common::String &txt) {
void cTxtStyle::setFontStyle(StyledTTFont &font) {
uint tempStyle = 0;
- if (bold)
+ if (_bold)
tempStyle |= StyledTTFont::STTF_BOLD;
- if (italic)
+ if (_italic)
tempStyle |= StyledTTFont::STTF_ITALIC;
- if (underline)
+ if (_underline)
tempStyle |= StyledTTFont::STTF_UNDERLINE;
- if (strikeout)
+ if (_strikeout)
tempStyle |= StyledTTFont::STTF_STRIKEOUT;
- if (sharp)
+ if (_sharp)
tempStyle |= StyledTTFont::STTF_SHARP;
font.setStyle(tempStyle);
@@ -268,27 +278,27 @@ void cTxtStyle::setFontStyle(StyledTTFont &font) {
void cTxtStyle::setFont(StyledTTFont &font) {
uint tempStyle = 0;
- if (bold)
+ if (_bold)
tempStyle |= StyledTTFont::STTF_BOLD;
- if (italic)
+ if (_italic)
tempStyle |= StyledTTFont::STTF_ITALIC;
- if (underline)
+ if (_underline)
tempStyle |= StyledTTFont::STTF_UNDERLINE;
- if (strikeout)
+ if (_strikeout)
tempStyle |= StyledTTFont::STTF_STRIKEOUT;
- if (sharp)
+ if (_sharp)
tempStyle |= StyledTTFont::STTF_SHARP;
- font.loadFont(fontname, size, tempStyle);
+ font.loadFont(_fontname, _size, tempStyle);
}
Graphics::Surface *TextRenderer::render(StyledTTFont &fnt, const Common::String &txt, cTxtStyle &style) {
style.setFontStyle(fnt);
- uint32 clr = _engine->_pixelFormat.RGBToColor(style.red, style.green, style.blue);
+ uint32 clr = _engine->_resourcePixelFormat.RGBToColor(style._red, style._green, style._blue);
return fnt.renderSolidText(txt, clr);
}
@@ -307,13 +317,13 @@ int32 TextRenderer::drawTxt(const Common::String &txt, cTxtStyle &fontStyle, Gra
dst.fillRect(Common::Rect(dst.w, dst.h), 0);
- uint32 clr = _engine->_pixelFormat.RGBToColor(fontStyle.red, fontStyle.green, fontStyle.blue);
+ uint32 clr = _engine->_resourcePixelFormat.RGBToColor(fontStyle._red, fontStyle._green, fontStyle._blue);
int16 w;
w = font.getStringWidth(txt);
- drawTxtWithJustify(txt, font, clr, dst, 0, fontStyle.justify);
+ drawTxtWithJustify(txt, font, clr, dst, 0, fontStyle._justify);
return w;
}
@@ -352,7 +362,7 @@ void TextRenderer::drawTxtInOneLine(const Common::String &text, Graphics::Surfac
int16 prevbufspace = 0, prevtxtspace = 0;
while (i < stringlen) {
- TxtJustify[currentline] = style.justify;
+ TxtJustify[currentline] = style._justify;
if (text[i] == '<') {
int16 ret = 0;
@@ -396,7 +406,7 @@ void TextRenderer::drawTxtInOneLine(const Common::String &text, Graphics::Surfac
if (ret & TXT_RET_HASSTBOX) {
Common::String buf3;
- buf3 = Common::String::format("%d", _engine->getScriptManager()->getStateValue(style.statebox));
+ buf3 = Common::String::format("%d", _engine->getScriptManager()->getStateValue(style._statebox));
buf += buf3;
textPosition += buf3.size();
}
@@ -452,15 +462,16 @@ void TextRenderer::drawTxtInOneLine(const Common::String &text, Graphics::Surfac
j++;
}
dx = 0;
+ Common::Rect empty;
for (int32 jj = 0; jj < j; jj++) {
if (TxtJustify[i] == TXT_JUSTIFY_LEFT)
- _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], dst, dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
+ _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], empty, dst, dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
else if (TxtJustify[i] == TXT_JUSTIFY_CENTER)
- _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], dst, ((dst.w - width) / 2) + dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
+ _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], empty, dst, ((dst.w - width) / 2) + dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
else if (TxtJustify[i] == TXT_JUSTIFY_RIGHT)
- _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], dst, dst.w - width + dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
+ _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], empty, dst, dst.w - width + dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
dx += TxtSurfaces[i][jj]->w;
}
@@ -495,10 +506,12 @@ Common::String readWideLine(Common::SeekableReadStream &stream) {
} else if (value >= 0x80 && value < 0x800) {
asciiString += (char)(0xC0 | ((value >> 6) & 0x1F));
asciiString += (char)(0x80 | (value & 0x3F));
- } else if (value >= 0x800 && value < 0x10000) {
+ } else if (value >= 0x800 && value < 0x10000 && value != 0xCCCC) {
asciiString += (char)(0xE0 | ((value >> 12) & 0xF));
asciiString += (char)(0x80 | ((value >> 6) & 0x3F));
asciiString += (char)(0x80 | (value & 0x3F));
+ } else if (value == 0xCCCC) {
+ // Ignore, this character is used as newline sometimes
} else if (value >= 0x10000 && value < 0x200000) {
asciiString += (char)(0xF0);
asciiString += (char)(0x80 | ((value >> 12) & 0x3F));
diff --git a/engines/zvision/text/text.h b/engines/zvision/text/text.h
index ecec3ccde6..c942b8141a 100644
--- a/engines/zvision/text/text.h
+++ b/engines/zvision/text/text.h
@@ -25,7 +25,7 @@
#define ZVISION_TEXT_H
#include "zvision/detection.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
#include "zvision/zvision.h"
namespace ZVision {
@@ -55,21 +55,25 @@ public:
void setFont(StyledTTFont &font);
public:
- Common::String fontname;
- txtJustify justify; // 0 - center, 1-left, 2-right
- int16 size;
- uint8 red; // 0-255
- uint8 green; // 0-255
- uint8 blue; // 0-255
- int8 newline;
- int8 escapement;
- bool italic;
- bool bold;
- bool underline;
- bool strikeout;
- bool skipcolor;
- int32 statebox;
- bool sharp;
+ Common::String _fontname;
+ txtJustify _justify; // 0 - center, 1-left, 2-right
+ int16 _size;
+ uint8 _red; // 0-255
+ uint8 _green; // 0-255
+ uint8 _blue; // 0-255
+#if 0
+ int8 _newline;
+ int8 _escapement;
+#endif
+ bool _italic;
+ bool _bold;
+ bool _underline;
+ bool _strikeout;
+#if 0
+ bool _skipcolor;
+#endif
+ int32 _statebox;
+ bool _sharp;
// char image ??
};
diff --git a/engines/zvision/graphics/truetype_font.cpp b/engines/zvision/text/truetype_font.cpp
index 2dbd7ca358..622a02a6a8 100644
--- a/engines/zvision/graphics/truetype_font.cpp
+++ b/engines/zvision/text/truetype_font.cpp
@@ -32,7 +32,7 @@
#include "zvision/zvision.h"
#include "zvision/graphics/render_manager.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
namespace ZVision {
@@ -54,105 +54,68 @@ bool StyledTTFont::loadFont(const Common::String &fontName, int32 point, uint st
}
bool StyledTTFont::loadFont(const Common::String &fontName, int32 point) {
+ struct FontStyle {
+ const char *zorkFont;
+ const char *fontBase;
+ const char *freeFontBase;
+ const char *freeFontItalicName;
+ };
+
+ const FontStyle systemFonts[] = {
+ { "*times new roman*", "times", "FreeSerif", "Italic" },
+ { "*times*", "times", "FreeSerif", "Italic" },
+ { "*century schoolbook*", "censcbk", "FreeSerif", "Italic" },
+ { "*garamond*", "gara", "FreeSerif", "Italic" },
+ { "*courier new*", "cour", "FreeMono", "Oblique" },
+ { "*courier*", "cour", "FreeMono", "Oblique" },
+ { "*ZorkDeath*", "cour", "FreeMono", "Oblique" },
+ { "*arial*", "arial", "FreeSans", "Oblique" },
+ { "*ZorkNormal*", "arial", "FreeSans", "Oblique" },
+ };
+
Common::String newFontName;
- if (fontName.matchString("*times new roman*", true) || fontName.matchString("*times*", true)) {
- if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC))
- newFontName = "timesbi.ttf";
- else if (_style & STTF_BOLD)
- newFontName = "timesbd.ttf";
- else if (_style & STTF_ITALIC)
- newFontName = "timesi.ttf";
- else
- newFontName = "times.ttf";
-
- } else if (fontName.matchString("*courier new*", true) || fontName.matchString("*courier*", true) || fontName.matchString("*ZorkDeath*", true)) {
- if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC))
- newFontName = "courbi.ttf";
- else if (_style & STTF_BOLD)
- newFontName = "courbd.ttf";
- else if (_style & STTF_ITALIC)
- newFontName = "couri.ttf";
- else
- newFontName = "cour.ttf";
-
- } else if (fontName.matchString("*century schoolbook*", true)) {
- if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC))
- newFontName = "censcbkbi.ttf";
- else if (_style & STTF_BOLD)
- newFontName = "censcbkbd.ttf";
- else if (_style & STTF_ITALIC)
- newFontName = "censcbki.ttf";
- else
- newFontName = "censcbk.ttf";
-
- } else if (fontName.matchString("*garamond*", true)) {
- if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC))
- newFontName = "garabi.ttf";
- else if (_style & STTF_BOLD)
- newFontName = "garabd.ttf";
- else if (_style & STTF_ITALIC)
- newFontName = "garai.ttf";
- else
- newFontName = "gara.ttf";
-
- } else if (fontName.matchString("*arial*", true) || fontName.matchString("*ZorkNormal*", true)) {
- if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC))
- newFontName = "arialbi.ttf";
- else if (_style & STTF_BOLD)
- newFontName = "arialbd.ttf";
- else if (_style & STTF_ITALIC)
- newFontName = "ariali.ttf";
- else
- newFontName = "arial.ttf";
+ Common::String freeFontName;
+
+ for (int i = 0; i < ARRAYSIZE(systemFonts); i++) {
+ if (fontName.matchString(systemFonts[i].zorkFont, true)) {
+ newFontName = systemFonts[i].fontBase;
+ freeFontName = systemFonts[i].freeFontBase;
+
+ if ((_style & STTF_BOLD) && (_style & STTF_ITALIC)) {
+ newFontName += "bi";
+ freeFontName += "Bold";
+ freeFontName += systemFonts[i].freeFontItalicName;
+ } else if (_style & STTF_BOLD) {
+ newFontName += "bd";
+ freeFontName += "Bold";
+ } else if (_style & STTF_ITALIC) {
+ newFontName += "i";
+ freeFontName += systemFonts[i].freeFontItalicName;
+ }
- } else {
+ newFontName += ".ttf";
+ freeFontName += ".ttf";
+ break;
+ }
+ }
+
+ if (newFontName.empty()) {
debug("Could not identify font: %s. Reverting to Arial", fontName.c_str());
newFontName = "arial.ttf";
+ freeFontName = "FreeSans.ttf";
}
bool sharp = (_style & STTF_SHARP) == STTF_SHARP;
- Common::File *file = _engine->getSearchManager()->openFile(newFontName);
-
- if (!file) {
- Common::SeekableReadStream *themeFile = nullptr;
- if (ConfMan.hasKey("themepath")) {
- Common::FSNode themePath(ConfMan.get("themepath"));
- if (themePath.exists()) {
- Common::FSNode scummModern = themePath.getChild("scummmodern.zip");
- if (scummModern.exists()) {
- themeFile = scummModern.createReadStream();
- }
- }
- }
- if (!themeFile) { // Fallback : Search for ScummModern.zip in SearchMan.
- themeFile = SearchMan.createReadStreamForMember("scummmodern.zip");
- }
- if (themeFile) {
- Common::Archive *themeArchive = Common::makeZipArchive(themeFile);
- if (themeArchive->hasFile("FreeSans.ttf")) {
- Common::SeekableReadStream *stream = nullptr;
- stream = themeArchive->createReadStreamForMember("FreeSans.ttf");
- Graphics::Font *_newFont = Graphics::loadTTFFont(*stream, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display
- if (_newFont) {
- if (!_font)
- delete _font;
- _font = _newFont;
- }
- if (stream)
- delete stream;
- }
- delete themeArchive;
- themeArchive = nullptr;
- }
- } else {
- Graphics::Font *_newFont = Graphics::loadTTFFont(*file, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display
- if (_newFont) {
- if (!_font)
- delete _font;
- _font = _newFont;
- }
- delete file;
+ Common::File file;
+ if (!file.open(newFontName) && !file.open(freeFontName) && !_engine->getSearchManager()->openFile(file, newFontName) && !_engine->getSearchManager()->openFile(file, freeFontName))
+ error("Unable to open font file %s (free alternative: %s)", newFontName.c_str(), freeFontName.c_str());
+
+ Graphics::Font *_newFont = Graphics::loadTTFFont(file, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display
+ if (_newFont) {
+ if (!_font)
+ delete _font;
+ _font = _newFont;
}
_fntName = fontName;
@@ -255,7 +218,7 @@ Graphics::Surface *StyledTTFont::renderSolidText(const Common::String &str, uint
if (_font) {
int16 w = _font->getStringWidth(str);
if (w && w < 1024) {
- tmp->create(w, _font->getFontHeight(), _engine->_pixelFormat);
+ tmp->create(w, _font->getFontHeight(), _engine->_resourcePixelFormat);
drawString(tmp, str, 0, 0, w, color);
}
}
diff --git a/engines/zvision/graphics/truetype_font.h b/engines/zvision/text/truetype_font.h
index b5fac4af8a..b5fac4af8a 100644
--- a/engines/zvision/graphics/truetype_font.h
+++ b/engines/zvision/text/truetype_font.h
diff --git a/engines/zvision/video/rlf_decoder.cpp b/engines/zvision/video/rlf_decoder.cpp
index bdb5dc18bc..db598a25b6 100644
--- a/engines/zvision/video/rlf_decoder.cpp
+++ b/engines/zvision/video/rlf_decoder.cpp
@@ -30,8 +30,6 @@
#include "common/debug.h"
#include "common/endian.h"
-#include "graphics/colormasks.h"
-
namespace ZVision {
RLFDecoder::~RLFDecoder() {
@@ -41,9 +39,13 @@ RLFDecoder::~RLFDecoder() {
bool RLFDecoder::loadStream(Common::SeekableReadStream *stream) {
close();
- addTrack(new RLFVideoTrack(stream));
-
- return true;
+ // Check if the stream is valid
+ if (stream && !stream->err() && stream->readUint32BE() == MKTAG('F', 'E', 'L', 'R')) {
+ addTrack(new RLFVideoTrack(stream));
+ return true;
+ } else {
+ return false;
+ }
}
RLFDecoder::RLFVideoTrack::RLFVideoTrack(Common::SeekableReadStream *stream)
@@ -54,7 +56,7 @@ RLFDecoder::RLFVideoTrack::RLFVideoTrack(Common::SeekableReadStream *stream)
_height(0),
_frameTime(0),
_frames(0),
- _curFrame(0),
+ _displayedFrame(-1),
_frameBufferByteSize(0) {
if (!readHeader()) {
@@ -62,7 +64,7 @@ RLFDecoder::RLFVideoTrack::RLFVideoTrack(Common::SeekableReadStream *stream)
return;
}
- _currentFrameBuffer.create(_width, _height, Graphics::createPixelFormat<565>());
+ _currentFrameBuffer.create(_width, _height, getPixelFormat());
_frameBufferByteSize = _width * _height * sizeof(uint16);
_frames = new Frame[_frameCount];
@@ -83,10 +85,6 @@ RLFDecoder::RLFVideoTrack::~RLFVideoTrack() {
}
bool RLFDecoder::RLFVideoTrack::readHeader() {
- if (_readStream->readUint32BE() != MKTAG('F', 'E', 'L', 'R')) {
- return false;
- }
-
// Read the header
_readStream->readUint32LE(); // Size1
_readStream->readUint32LE(); // Unknown1
@@ -163,16 +161,11 @@ bool RLFDecoder::RLFVideoTrack::seek(const Audio::Timestamp &time) {
uint frame = getFrameAtTime(time);
assert(frame < (int)_frameCount);
- if ((uint)_curFrame == frame)
+ if ((uint)_displayedFrame == frame)
return true;
- if (frame < 0) {
- _curFrame = 0;
- return false;
- }
-
- int closestFrame = _curFrame;
- int distance = (int)frame - _curFrame;
+ int closestFrame = _displayedFrame;
+ int distance = (int)frame - closestFrame;
if (distance < 0) {
for (uint i = 0; i < _completeFrames.size(); ++i) {
@@ -196,19 +189,18 @@ bool RLFDecoder::RLFVideoTrack::seek(const Audio::Timestamp &time) {
applyFrameToCurrent(i);
}
- _curFrame = frame;
+ _displayedFrame = frame - 1;
return true;
}
const Graphics::Surface *RLFDecoder::RLFVideoTrack::decodeNextFrame() {
- // When an animation ends, rewind
- if (_curFrame == (int)_frameCount)
- seek(Audio::Timestamp(0, getFrameRate().toInt()));
+ if (_displayedFrame >= (int)_frameCount)
+ return NULL;
- applyFrameToCurrent(_curFrame);
+ _displayedFrame++;
+ applyFrameToCurrent(_displayedFrame);
- _curFrame++;
return &_currentFrameBuffer;
}
@@ -242,10 +234,7 @@ void RLFDecoder::RLFVideoTrack::decodeMaskedRunLengthEncoding(int8 *source, int8
return;
}
- byte r, g, b;
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(READ_LE_UINT16(source + sourceOffset), r, g, b);
- uint16 destColor = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b);
- WRITE_UINT16(dest + destOffset, destColor);
+ WRITE_UINT16(dest + destOffset, READ_LE_UINT16(source + sourceOffset));
sourceOffset += 2;
destOffset += 2;
@@ -289,10 +278,7 @@ void RLFDecoder::RLFVideoTrack::decodeSimpleRunLengthEncoding(int8 *source, int8
return;
}
- byte r, g, b;
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(READ_LE_UINT16(source + sourceOffset), r, g, b);
- uint16 destColor = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b);
- WRITE_UINT16(dest + destOffset, destColor);
+ WRITE_UINT16(dest + destOffset, READ_LE_UINT16(source + sourceOffset));
sourceOffset += 2;
destOffset += 2;
@@ -306,9 +292,7 @@ void RLFDecoder::RLFVideoTrack::decodeSimpleRunLengthEncoding(int8 *source, int8
return;
}
- byte r, g, b;
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(READ_LE_UINT16(source + sourceOffset), r, g, b);
- uint16 sampleColor = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b);
+ uint16 sampleColor = READ_LE_UINT16(source + sourceOffset);
sourceOffset += 2;
numberOfCopy = numberOfSamples + 2;
diff --git a/engines/zvision/video/rlf_decoder.h b/engines/zvision/video/rlf_decoder.h
index f0f31c2128..8b8cbaecd5 100644
--- a/engines/zvision/video/rlf_decoder.h
+++ b/engines/zvision/video/rlf_decoder.h
@@ -45,15 +45,15 @@ private:
uint16 getWidth() const { return _width; }
uint16 getHeight() const { return _height; }
- Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); /*RGB 565*/ }
- int getCurFrame() const { return _curFrame; }
+ Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); /* RGB 555 */ }
+ int getCurFrame() const { return _displayedFrame; }
int getFrameCount() const { return _frameCount; }
const Graphics::Surface *decodeNextFrame();
bool isSeekable() const { return true; }
bool seek(const Audio::Timestamp &time);
protected:
- Common::Rational getFrameRate() const { return Common::Rational(60, _frameTime); }
+ Common::Rational getFrameRate() const { return Common::Rational(1000, _frameTime); }
private:
enum EncodingType {
@@ -121,7 +121,7 @@ private:
Frame *_frames;
Common::Array<uint> _completeFrames;
- int _curFrame;
+ int _displayedFrame;
Graphics::Surface _currentFrameBuffer;
uint32 _frameBufferByteSize;
diff --git a/engines/zvision/video/video.cpp b/engines/zvision/video/video.cpp
index 189fb22194..0913b28818 100644
--- a/engines/zvision/video/video.cpp
+++ b/engines/zvision/video/video.cpp
@@ -29,7 +29,8 @@
#include "zvision/zvision.h"
#include "zvision/core/clock.h"
#include "zvision/graphics/render_manager.h"
-#include "zvision/graphics/subtitles.h"
+#include "zvision/scripting//script_manager.h"
+#include "zvision/text/subtitles.h"
#include "zvision/video/rlf_decoder.h"
#include "zvision/video/zork_avi_decoder.h"
@@ -48,7 +49,12 @@ Video::VideoDecoder *ZVision::loadAnimation(const Common::String &fileName) {
error("Unknown suffix for animation %s", fileName.c_str());
Common::File *_file = getSearchManager()->openFile(tmpFileName);
- animation->loadStream(_file);
+ if (!_file)
+ error("Error opening %s", tmpFileName.c_str());
+
+ bool loaded = animation->loadStream(_file);
+ if (!loaded)
+ error("Error loading animation %s", tmpFileName.c_str());
return animation;
}
@@ -70,6 +76,7 @@ void ZVision::playVideo(Video::VideoDecoder &vid, const Common::Rect &destRect,
uint16 y = _workingWindow.top + dst.top;
uint16 finalWidth = dst.width() < _workingWindow.width() ? dst.width() : _workingWindow.width();
uint16 finalHeight = dst.height() < _workingWindow.height() ? dst.height() : _workingWindow.height();
+ bool showSubs = (_scriptManager->getStateValue(StateKey_Subtitles) == 1);
_clock.stop();
vid.start();
@@ -101,7 +108,7 @@ void ZVision::playVideo(Video::VideoDecoder &vid, const Common::Rect &destRect,
if (vid.needsUpdate()) {
const Graphics::Surface *frame = vid.decodeNextFrame();
- if (sub)
+ if (sub && showSubs)
sub->process(vid.getCurFrame());
if (frame) {
@@ -109,7 +116,8 @@ void ZVision::playVideo(Video::VideoDecoder &vid, const Common::Rect &destRect,
_renderManager->scaleBuffer(frame->getPixels(), scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, scaled->w, scaled->h);
frame = scaled;
}
- _system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, x, y, finalWidth, finalHeight);
+ Common::Rect rect = Common::Rect(x, y, x + finalWidth, y + finalHeight);
+ _renderManager->copyToScreen(*frame, rect, 0, 0);
_renderManager->processSubs(0);
}
}
diff --git a/engines/zvision/video/zork_avi_decoder.cpp b/engines/zvision/video/zork_avi_decoder.cpp
index 67fab0a114..5618250d79 100644
--- a/engines/zvision/video/zork_avi_decoder.cpp
+++ b/engines/zvision/video/zork_avi_decoder.cpp
@@ -45,8 +45,14 @@ void ZorkAVIDecoder::ZorkAVIAudioTrack::queueSound(Common::SeekableReadStream *s
RawChunkStream::RawChunk chunk = decoder->readNextChunk(stream);
delete stream;
- if (chunk.data)
- _audStream->queueBuffer((byte *)chunk.data, chunk.size, DisposeAfterUse::YES, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_STEREO);
+ if (chunk.data) {
+ byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO;
+#ifdef SCUMM_LITTLE_ENDIAN
+ // RawChunkStream produces native endianness int16
+ flags |= Audio::FLAG_LITTLE_ENDIAN;
+#endif
+ _audStream->queueBuffer((byte *)chunk.data, chunk.size, DisposeAfterUse::YES, flags);
+ }
} else {
AVIAudioTrack::queueSound(stream);
}
diff --git a/engines/zvision/zvision.cpp b/engines/zvision/zvision.cpp
index c32cceb26e..54991aced3 100644
--- a/engines/zvision/zvision.cpp
+++ b/engines/zvision/zvision.cpp
@@ -27,13 +27,13 @@
#include "zvision/scripting/script_manager.h"
#include "zvision/graphics/render_manager.h"
#include "zvision/graphics/cursors/cursor_manager.h"
-#include "zvision/core/save_manager.h"
+#include "zvision/file/save_manager.h"
#include "zvision/text/string_manager.h"
#include "zvision/detection.h"
-#include "zvision/core/menu.h"
+#include "zvision/scripting/menu.h"
#include "zvision/file/search_manager.h"
#include "zvision/text/text.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
#include "zvision/sound/midi.h"
#include "zvision/file/zfs_archive.h"
@@ -46,42 +46,41 @@
#include "common/system.h"
#include "common/file.h"
+#include "gui/message.h"
#include "engines/util.h"
-
#include "audio/mixer.h"
namespace ZVision {
-#define ZVISION_SETTINGS_KEYS_COUNT 17
+#define ZVISION_SETTINGS_KEYS_COUNT 11
struct zvisionIniSettings {
const char *name;
int16 slot;
- int16 deflt;
+ int16 defaultValue; // -1: use the bool value
+ bool defaultBoolValue;
+ bool allowEditing;
} settingsKeys[ZVISION_SETTINGS_KEYS_COUNT] = {
- {"ZVision_KeyboardTurnSpeed", StateKey_KbdRotateSpeed, 5},
- {"ZVision_PanaRotateSpeed", StateKey_RotateSpeed, 540},
- {"ZVision_QSoundEnabled", StateKey_Qsound, 1},
- {"ZVision_VenusEnabled", StateKey_VenusEnable, 1},
- {"ZVision_HighQuality", StateKey_HighQuality, 1},
- {"ZVision_Platform", StateKey_Platform, 0},
- {"ZVision_InstallLevel", StateKey_InstallLevel, 0},
- {"ZVision_CountryCode", StateKey_CountryCode, 0},
- {"ZVision_CPU", StateKey_CPU, 1},
- {"ZVision_MovieCursor", StateKey_MovieCursor, 1},
- {"ZVision_NoAnimWhileTurning", StateKey_NoTurnAnim, 0},
- {"ZVision_Win958", StateKey_WIN958, 0},
- {"ZVision_ShowErrorDialogs", StateKey_ShowErrorDlg, 0},
- {"ZVision_ShowSubtitles", StateKey_Subtitles, 1},
- {"ZVision_DebugCheats", StateKey_DebugCheats, 0},
- {"ZVision_JapaneseFonts", StateKey_JapanFonts, 0},
- {"ZVision_Brightness", StateKey_Brightness, 0}
+ // Hardcoded settings
+ {"countrycode", StateKey_CountryCode, 0, false, false}, // always 0 = US, subtitles are shown for codes 0 - 4, unused
+ {"lineskipvideo", StateKey_VideoLineSkip, 0, false, false}, // video line skip, 0 = default, 1 = always, 2 = pixel double when possible, unused
+ {"installlevel", StateKey_InstallLevel, 0, false, false}, // 0 = full, checked by universe.scr
+ {"highquality", StateKey_HighQuality, -1, true, false}, // high panorama quality, unused
+ {"qsoundenabled", StateKey_Qsound, -1, true, false}, // 1 = enable QSound - TODO: not supported yet
+ {"debugcheats", StateKey_DebugCheats, -1, true, false}, // always start with the GOxxxx cheat enabled
+ // Editable settings
+ {"keyboardturnspeed", StateKey_KbdRotateSpeed, 5, false, true},
+ {"panarotatespeed", StateKey_RotateSpeed, 540, false, true}, // checked by universe.scr
+ {"noanimwhileturning", StateKey_NoTurnAnim, -1, false, true}, // toggle playing animations during pana rotation
+ {"venusenabled", StateKey_VenusEnable, -1, true, true},
+ {"subtitles", StateKey_Subtitles, -1, true, true}
};
ZVision::ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc)
: Engine(syst),
_gameDescription(gameDesc),
- _pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), /*RGB 565*/
+ _resourcePixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0), /* RGB 555 */
+ _screenPixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), /* RGB 565 */
_desiredFrameTime(33), /* ~30 fps */
_clock(_system),
_scriptManager(nullptr),
@@ -95,12 +94,14 @@ ZVision::ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc)
_menu(nullptr),
_searchManager(nullptr),
_textRenderer(nullptr),
- _halveDelay(false),
+ _doubleFPS(false),
_audioId(0),
_frameRenderDelay(2),
_keyboardVelocity(0),
_mouseVelocity(0),
- _videoIsPlaying(false) {
+ _videoIsPlaying(false),
+ _renderedFrameCount(0),
+ _fps(0) {
debug(1, "ZVision::ZVision");
@@ -124,24 +125,45 @@ ZVision::~ZVision() {
delete _cursorManager;
delete _stringManager;
delete _saveManager;
- delete _renderManager;
delete _scriptManager;
+ delete _renderManager; // should be deleted after the script manager
delete _rnd;
delete _midiManager;
+ getTimerManager()->removeTimerProc(&fpsTimerCallback);
+
// Remove all of our debug levels
DebugMan.clearAllDebugChannels();
}
void ZVision::registerDefaultSettings() {
- for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++)
- ConfMan.registerDefault(settingsKeys[i].name, settingsKeys[i].deflt);
+ for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++) {
+ if (settingsKeys[i].allowEditing) {
+ if (settingsKeys[i].defaultValue >= 0)
+ ConfMan.registerDefault(settingsKeys[i].name, settingsKeys[i].defaultValue);
+ else
+ ConfMan.registerDefault(settingsKeys[i].name, settingsKeys[i].defaultBoolValue);
+ }
+ }
+
+ ConfMan.registerDefault("originalsaveload", false);
ConfMan.registerDefault("doublefps", false);
}
void ZVision::loadSettings() {
- for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++)
- _scriptManager->setStateValue(settingsKeys[i].slot, ConfMan.getInt(settingsKeys[i].name));
+ int16 value = 0;
+ bool boolValue = false;
+
+ for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++) {
+ if (settingsKeys[i].defaultValue >= 0) {
+ value = (settingsKeys[i].allowEditing) ? ConfMan.getInt(settingsKeys[i].name) : settingsKeys[i].defaultValue;
+ } else {
+ boolValue = (settingsKeys[i].allowEditing) ? ConfMan.getBool(settingsKeys[i].name) : settingsKeys[i].defaultBoolValue;
+ value = (boolValue) ? 1 : 0;
+ }
+
+ _scriptManager->setStateValue(settingsKeys[i].slot, value);
+ }
if (getGameId() == GID_NEMESIS)
_scriptManager->setStateValue(StateKey_ExecScopeStyle, 1);
@@ -150,8 +172,15 @@ void ZVision::loadSettings() {
}
void ZVision::saveSettings() {
- for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++)
- ConfMan.setInt(settingsKeys[i].name, _scriptManager->getStateValue(settingsKeys[i].slot));
+ for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++) {
+ if (settingsKeys[i].allowEditing) {
+ if (settingsKeys[i].defaultValue >= 0)
+ ConfMan.setInt(settingsKeys[i].name, _scriptManager->getStateValue(settingsKeys[i].slot));
+ else
+ ConfMan.setBool(settingsKeys[i].name, (_scriptManager->getStateValue(settingsKeys[i].slot) == 1));
+ }
+ }
+
ConfMan.flushToDisk();
}
@@ -182,17 +211,17 @@ void ZVision::initialize() {
} else if (_gameDescription->gameId == GID_NEMESIS)
_searchManager->loadZix("NEMESIS.ZIX");
- initGraphics(WINDOW_WIDTH, WINDOW_HEIGHT, true, &_pixelFormat);
+ initGraphics(WINDOW_WIDTH, WINDOW_HEIGHT, true, &_screenPixelFormat);
// Register random source
_rnd = new Common::RandomSource("zvision");
// Create managers
_scriptManager = new ScriptManager(this);
- _renderManager = new RenderManager(this, WINDOW_WIDTH, WINDOW_HEIGHT, _workingWindow, _pixelFormat);
+ _renderManager = new RenderManager(this, WINDOW_WIDTH, WINDOW_HEIGHT, _workingWindow, _resourcePixelFormat, _doubleFPS);
_saveManager = new SaveManager(this);
_stringManager = new StringManager(this);
- _cursorManager = new CursorManager(this, &_pixelFormat);
+ _cursorManager = new CursorManager(this, _resourcePixelFormat);
_textRenderer = new TextRenderer(this);
_midiManager = new MidiManager();
@@ -212,7 +241,10 @@ void ZVision::initialize() {
// Create debugger console. It requires GFX to be initialized
_console = new Console(this);
- _halveDelay = ConfMan.getBool("doublefps");
+ _doubleFPS = ConfMan.getBool("doublefps");
+
+ // Initialize FPS timer callback
+ getTimerManager()->installTimerProc(&fpsTimerCallback, 1000000, this, "zvisionFPS");
}
Common::Error ZVision::run() {
@@ -222,6 +254,22 @@ Common::Error ZVision::run() {
if (ConfMan.hasKey("save_slot"))
_saveManager->loadGame(ConfMan.getInt("save_slot"));
+ // Before starting, make absolutely sure that the user has copied the needed fonts
+ if (!Common::File::exists("arial.ttf") && !Common::File::exists("FreeSans.ttf") && !_searchManager->hasFile("arial.ttf") && !_searchManager->hasFile("FreeSans.ttf") ) {
+ GUI::MessageDialog dialog(
+ "Before playing this game, you'll need to copy the required "
+ "fonts into ScummVM's extras directory, or into the game directory. "
+ "On Windows, you'll need the following font files from the Windows "
+ "font directory: Times New Roman, Century Schoolbook, Garamond, "
+ "Courier New and Arial. Alternatively, you can download the GNU "
+ "FreeFont package. You'll need all the fonts from that package, "
+ "i.e., FreeMono, FreeSans and FreeSerif."
+ );
+ dialog.runModal();
+ quitGame();
+ return Common::kUnknownError;
+ }
+
// Main loop
while (!shouldQuit()) {
_clock.update();
@@ -231,7 +279,7 @@ Common::Error ZVision::run() {
_cursorManager->setItemID(_scriptManager->getStateValue(StateKey_InventoryItem));
processEvents();
- updateRotation();
+ _renderManager->updateRotation();
_scriptManager->update(deltaTime);
_menu->process(deltaTime);
@@ -243,8 +291,9 @@ Common::Error ZVision::run() {
_renderManager->renderSceneToScreen();
// Update the screen
- if (_frameRenderDelay <= 0) {
+ if (canRender()) {
_system->updateScreen();
+ _renderedFrameCount++;
} else {
_frameRenderDelay--;
}
@@ -254,85 +303,18 @@ Common::Error ZVision::run() {
// Ensure non-negative
delay = delay < 0 ? 0 : delay;
- if (_halveDelay) {
+ if (_doubleFPS) {
delay >>= 1;
}
- _system->delayMillis(delay);
- }
-
- return Common::kNoError;
-}
-
-bool ZVision::askQuestion(const Common::String &str) {
- uint16 msgid = _renderManager->createSubArea();
- _renderManager->updateSubArea(msgid, str);
- _renderManager->processSubs(0);
- _renderManager->renderSceneToScreen();
- _clock.stop();
-
- int result = 0;
-
- while (result == 0) {
- Common::Event evnt;
- while (_eventMan->pollEvent(evnt)) {
- if (evnt.type == Common::EVENT_KEYDOWN) {
- switch (evnt.kbd.keycode) {
- case Common::KEYCODE_y:
- result = 2;
- break;
- case Common::KEYCODE_n:
- result = 1;
- break;
- default:
- break;
- }
- }
+ if (canSaveGameStateCurrently() && shouldPerformAutoSave(_saveManager->getLastSaveTime())) {
+ _saveManager->autoSave();
}
- _system->updateScreen();
- if (_halveDelay)
- _system->delayMillis(33);
- else
- _system->delayMillis(66);
- }
- _renderManager->deleteSubArea(msgid);
- _clock.start();
- return result == 2;
-}
-void ZVision::delayedMessage(const Common::String &str, uint16 milsecs) {
- uint16 msgid = _renderManager->createSubArea();
- _renderManager->updateSubArea(msgid, str);
- _renderManager->processSubs(0);
- _renderManager->renderSceneToScreen();
- _clock.stop();
-
- uint32 stopTime = _system->getMillis() + milsecs;
- while (_system->getMillis() < stopTime) {
- Common::Event evnt;
- while (_eventMan->pollEvent(evnt)) {
- if (evnt.type == Common::EVENT_KEYDOWN &&
- (evnt.kbd.keycode == Common::KEYCODE_SPACE ||
- evnt.kbd.keycode == Common::KEYCODE_RETURN ||
- evnt.kbd.keycode == Common::KEYCODE_ESCAPE))
- break;
- }
- _system->updateScreen();
- if (_halveDelay)
- _system->delayMillis(33);
- else
- _system->delayMillis(66);
+ _system->delayMillis(delay);
}
- _renderManager->deleteSubArea(msgid);
- _clock.start();
-}
-void ZVision::timedMessage(const Common::String &str, uint16 milsecs) {
- uint16 msgid = _renderManager->createSubArea();
- _renderManager->updateSubArea(msgid, str);
- _renderManager->processSubs(0);
- _renderManager->renderSceneToScreen();
- _renderManager->deleteSubArea(msgid, milsecs);
+ return Common::kNoError;
}
void ZVision::pauseEngineIntern(bool pause) {
@@ -349,10 +331,6 @@ Common::String ZVision::generateSaveFileName(uint slot) {
return Common::String::format("%s.%03u", _targetName.c_str(), slot);
}
-Common::String ZVision::generateAutoSaveFileName() {
- return Common::String::format("%s.auto", _targetName.c_str());
-}
-
void ZVision::setRenderDelay(uint delay) {
_frameRenderDelay = delay;
}
@@ -361,188 +339,23 @@ bool ZVision::canRender() {
return _frameRenderDelay <= 0;
}
-void ZVision::updateRotation() {
- int16 _velocity = _mouseVelocity + _keyboardVelocity;
-
- if (_halveDelay)
- _velocity /= 2;
-
- if (_velocity) {
- RenderTable::RenderState renderState = _renderManager->getRenderTable()->getRenderState();
- if (renderState == RenderTable::PANORAMA) {
- int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos);
-
- int16 newPosition = startPosition + (_renderManager->getRenderTable()->getPanoramaReverse() ? -_velocity : _velocity);
-
- int16 zeroPoint = _renderManager->getRenderTable()->getPanoramaZeroPoint();
- if (startPosition >= zeroPoint && newPosition < zeroPoint)
- _scriptManager->setStateValue(StateKey_Rounds, _scriptManager->getStateValue(StateKey_Rounds) - 1);
- if (startPosition <= zeroPoint && newPosition > zeroPoint)
- _scriptManager->setStateValue(StateKey_Rounds, _scriptManager->getStateValue(StateKey_Rounds) + 1);
-
- int16 screenWidth = _renderManager->getBkgSize().x;
- if (screenWidth)
- newPosition %= screenWidth;
-
- if (newPosition < 0)
- newPosition += screenWidth;
-
- _renderManager->setBackgroundPosition(newPosition);
- } else if (renderState == RenderTable::TILT) {
- int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos);
-
- int16 newPosition = startPosition + _velocity;
-
- int16 screenHeight = _renderManager->getBkgSize().y;
- int16 tiltGap = _renderManager->getRenderTable()->getTiltGap();
-
- if (newPosition >= (screenHeight - tiltGap))
- newPosition = screenHeight - tiltGap;
- if (newPosition <= tiltGap)
- newPosition = tiltGap;
-
- _renderManager->setBackgroundPosition(newPosition);
- }
- }
+GUI::Debugger *ZVision::getDebugger() {
+ return _console;
}
-void ZVision::checkBorders() {
- RenderTable::RenderState renderState = _renderManager->getRenderTable()->getRenderState();
- if (renderState == RenderTable::PANORAMA) {
- int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos);
-
- int16 newPosition = startPosition;
+void ZVision::syncSoundSettings() {
+ Engine::syncSoundSettings();
- int16 screenWidth = _renderManager->getBkgSize().x;
-
- if (screenWidth)
- newPosition %= screenWidth;
-
- if (newPosition < 0)
- newPosition += screenWidth;
-
- if (startPosition != newPosition)
- _renderManager->setBackgroundPosition(newPosition);
- } else if (renderState == RenderTable::TILT) {
- int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos);
-
- int16 newPosition = startPosition;
-
- int16 screenHeight = _renderManager->getBkgSize().y;
- int16 tiltGap = _renderManager->getRenderTable()->getTiltGap();
-
- if (newPosition >= (screenHeight - tiltGap))
- newPosition = screenHeight - tiltGap;
- if (newPosition <= tiltGap)
- newPosition = tiltGap;
-
- if (startPosition != newPosition)
- _renderManager->setBackgroundPosition(newPosition);
- }
-}
-
-void ZVision::rotateTo(int16 _toPos, int16 _time) {
- if (_renderManager->getRenderTable()->getRenderState() != RenderTable::PANORAMA)
- return;
-
- if (_time == 0)
- _time = 1;
-
- int32 maxX = _renderManager->getBkgSize().x;
- int32 curX = _renderManager->getCurrentBackgroundOffset();
- int32 dx = 0;
-
- if (curX == _toPos)
- return;
-
- if (curX > _toPos) {
- if (curX - _toPos > maxX / 2)
- dx = (_toPos + (maxX - curX)) / _time;
- else
- dx = -(curX - _toPos) / _time;
- } else {
- if (_toPos - curX > maxX / 2)
- dx = -((maxX - _toPos) + curX) / _time;
- else
- dx = (_toPos - curX) / _time;
- }
-
- _clock.stop();
-
- for (int16 i = 0; i <= _time; i++) {
- if (i == _time)
- curX = _toPos;
- else
- curX += dx;
-
- if (curX < 0)
- curX = maxX - curX;
- else if (curX >= maxX)
- curX %= maxX;
-
- _renderManager->setBackgroundPosition(curX);
-
- _renderManager->prepareBackground();
- _renderManager->renderSceneToScreen();
-
- _system->updateScreen();
-
- _system->delayMillis(500 / _time);
- }
-
- _clock.start();
-}
-
-void ZVision::menuBarEnable(uint16 menus) {
- if (_menu)
- _menu->setEnable(menus);
-}
-
-uint16 ZVision::getMenuBarEnable() {
- if (_menu)
- return _menu->getEnable();
- return 0;
-}
-
-bool ZVision::ifQuit() {
- if (askQuestion(_stringManager->getTextLine(StringManager::ZVISION_STR_EXITPROMT))) {
- quitGame();
- return true;
- }
- return false;
-}
-
-void ZVision::pushKeyToCheatBuf(uint8 key) {
- for (int i = 0; i < KEYBUF_SIZE - 1; i++)
- _cheatBuffer[i] = _cheatBuffer[i + 1];
-
- _cheatBuffer[KEYBUF_SIZE - 1] = key;
+ _scriptManager->setStateValue(StateKey_Subtitles, ConfMan.getBool("subtitles") ? 1 : 0);
}
-bool ZVision::checkCode(const char *code) {
- int codeLen = strlen(code);
-
- if (codeLen > KEYBUF_SIZE)
- return false;
-
- for (int i = 0; i < codeLen; i++)
- if (code[i] != _cheatBuffer[KEYBUF_SIZE - codeLen + i] && code[i] != '?')
- return false;
-
- return true;
-}
-
-uint8 ZVision::getBufferedKey(uint8 pos) {
- if (pos >= KEYBUF_SIZE)
- return 0;
- else
- return _cheatBuffer[KEYBUF_SIZE - pos - 1];
+void ZVision::fpsTimerCallback(void *refCon) {
+ ((ZVision *)refCon)->fpsTimer();
}
-void ZVision::showDebugMsg(const Common::String &msg, int16 delay) {
- uint16 msgid = _renderManager->createSubArea();
- _renderManager->updateSubArea(msgid, msg);
- _renderManager->deleteSubArea(msgid, delay);
+void ZVision::fpsTimer() {
+ _fps = _renderedFrameCount;
+ _renderedFrameCount = 0;
}
} // End of namespace ZVision
diff --git a/engines/zvision/zvision.h b/engines/zvision/zvision.h
index 7ea10ed64d..ad22ddaaa2 100644
--- a/engines/zvision/zvision.h
+++ b/engines/zvision/zvision.h
@@ -41,6 +41,17 @@ namespace Video {
class VideoDecoder;
}
+/**
+ * This is the namespace of the ZVision engine.
+ *
+ * Status of this engine: complete
+ *
+ * Games using this engine:
+ * - Zork Nemesis: The Forbidden Lands
+ * - Zork: Grand Inquisitor
+ *
+ */
+
namespace ZVision {
struct ZVisionGameDescription;
@@ -68,7 +79,8 @@ public:
* edges of this Rectangle
*/
Common::Rect _workingWindow;
- const Graphics::PixelFormat _pixelFormat;
+ const Graphics::PixelFormat _resourcePixelFormat;
+ const Graphics::PixelFormat _screenPixelFormat;
private:
enum {
@@ -118,9 +130,11 @@ private:
Common::Event _event;
int _frameRenderDelay;
+ int _renderedFrameCount;
+ int _fps;
int16 _mouseVelocity;
int16 _keyboardVelocity;
- bool _halveDelay;
+ bool _doubleFPS;
bool _videoIsPlaying;
uint8 _cheatBuffer[KEYBUF_SIZE];
@@ -154,15 +168,32 @@ public:
MidiManager *getMidiManager() const {
return _midiManager;
}
+ MenuHandler *getMenuHandler() const {
+ return _menu;
+ }
Common::RandomSource *getRandomSource() const {
return _rnd;
}
ZVisionGameId getGameId() const {
return _gameDescription->gameId;
}
+ int16 getKeyboardVelocity() const {
+ return _keyboardVelocity;
+ }
+ int16 getMouseVelocity() const {
+ return _mouseVelocity;
+ }
uint8 getZvisionKey(Common::KeyCode scummKeyCode);
+ void startClock() {
+ _clock.start();
+ }
+
+ void stopClock() {
+ _clock.stop();
+ }
+
/**
* Play a video until it is finished. This is a blocking call. It will call
* _clock.stop() when the video starts and _clock.start() when the video finishes.
@@ -175,29 +206,24 @@ public:
void playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &destRect = Common::Rect(0, 0, 0, 0), bool skippable = true, Subtitle *sub = NULL);
Video::VideoDecoder *loadAnimation(const Common::String &fileName);
- void rotateTo(int16 to, int16 time);
-
Common::String generateSaveFileName(uint slot);
- Common::String generateAutoSaveFileName();
-
- bool askQuestion(const Common::String &str);
- void delayedMessage(const Common::String &str, uint16 milsecs);
- void timedMessage(const Common::String &str, uint16 milsecs);
void setRenderDelay(uint);
bool canRender();
+ static void fpsTimerCallback(void *refCon);
+ void fpsTimer();
+ int getFPS() const {
+ return _fps;
+ }
+
+ GUI::Debugger *getDebugger();
+ void syncSoundSettings();
void loadSettings();
void saveSettings();
- void menuBarEnable(uint16 menus);
- uint16 getMenuBarEnable();
-
bool ifQuit();
- void checkBorders();
- void showDebugMsg(const Common::String &msg, int16 delay = 3000);
-
// Engine features
bool hasFeature(EngineFeature f) const;
bool canLoadGameStateCurrently();
@@ -214,7 +240,6 @@ private:
void processEvents();
void onMouseMove(const Common::Point &pos);
- void updateRotation();
void registerDefaultSettings();
void shortKeys(Common::Event);
diff --git a/gui/credits.h b/gui/credits.h
index 5b33797a63..c7d9199db9 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -324,6 +324,8 @@ static const char *credits[] = {
"",
"C1""ZVision",
"C0""Adrian Astley",
+"C0""Filippos Karapetis",
+"C0""Anton Yarcev",
"",
"",
"C1""Backend Teams",
@@ -630,6 +632,18 @@ static const char *credits[] = {
"C0""Alejandro G\363mez de la Mu\361oza",
"C2""Soltys Spanish translation",
"",
+"C1""CGE2",
+"A0""Arnaud Boutonne",
+"C0""Arnaud Boutonn\351",
+"C2""Sfinx English translation",
+"C0""Thierry Crozat",
+"C2""Sfinx English translation",
+"A0""Peter Bozso",
+"C0""Peter Bozs\363",
+"C2""Sfinx English translation editor",
+"C0""Ryan Clark",
+"C2""Sfinx English translation editor",
+"",
"C1""Drascula",
"C0""Thierry Crozat",
"C2""Improve French translation",
diff --git a/gui/debugger.cpp b/gui/debugger.cpp
index 216bd626fe..466681e89d 100644
--- a/gui/debugger.cpp
+++ b/gui/debugger.cpp
@@ -522,11 +522,25 @@ struct ArchiveMemberLess {
bool Debugger::cmdMd5(int argc, const char **argv) {
if (argc < 2) {
- debugPrintf("md5 <filename | pattern>\n");
+ debugPrintf("md5 [-n length] <filename | pattern>\n");
} else {
+ uint32 length = 0;
+ uint paramOffset = 0;
+
+ // If the user supplied an -n parameter, set the bytes to read
+ if (!strcmp(argv[1], "-n")) {
+ // Make sure that we have at least two more parameters
+ if (argc < 4) {
+ debugPrintf("md5 [-n length] <filename | pattern>\n");
+ return true;
+ }
+ length = atoi(argv[2]);
+ paramOffset = 2;
+ }
+
// Assume that spaces are part of a single filename.
- Common::String filename = argv[1];
- for (int i = 2; i < argc; i++) {
+ Common::String filename = argv[1 + paramOffset];
+ for (int i = 2 + paramOffset; i < argc; i++) {
filename = filename + " " + argv[i];
}
Common::ArchiveMemberList list;
@@ -536,9 +550,9 @@ bool Debugger::cmdMd5(int argc, const char **argv) {
} else {
sort(list.begin(), list.end(), ArchiveMemberLess());
for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) {
- Common::ReadStream *stream = (*iter)->createReadStream();
- Common::String md5 = Common::computeStreamMD5AsString(*stream, 0);
- debugPrintf("%s %s\n", md5.c_str(), (*iter)->getDisplayName().c_str());
+ Common::SeekableReadStream *stream = (*iter)->createReadStream();
+ Common::String md5 = Common::computeStreamMD5AsString(*stream, length);
+ debugPrintf("%s %s %d\n", md5.c_str(), (*iter)->getDisplayName().c_str(), stream->size());
delete stream;
}
}
@@ -548,11 +562,25 @@ bool Debugger::cmdMd5(int argc, const char **argv) {
bool Debugger::cmdMd5Mac(int argc, const char **argv) {
if (argc < 2) {
- debugPrintf("md5mac <base filename>\n");
+ debugPrintf("md5mac [-n length] <base filename>\n");
} else {
+ uint32 length = 0;
+ uint paramOffset = 0;
+
+ // If the user supplied an -n parameter, set the bytes to read
+ if (!strcmp(argv[1], "-n")) {
+ // Make sure that we have at least two more parameters
+ if (argc < 4) {
+ debugPrintf("md5mac [-n length] <base filename>\n");
+ return true;
+ }
+ length = atoi(argv[2]);
+ paramOffset = 2;
+ }
+
// Assume that spaces are part of a single filename.
- Common::String filename = argv[1];
- for (int i = 2; i < argc; i++) {
+ Common::String filename = argv[1 + paramOffset];
+ for (int i = 2 + paramOffset; i < argc; i++) {
filename = filename + " " + argv[i];
}
Common::MacResManager macResMan;
@@ -568,13 +596,13 @@ bool Debugger::cmdMd5Mac(int argc, const char **argv) {
} else {
// The resource fork is probably the most relevant one.
if (macResMan.hasResFork()) {
- Common::String md5 = macResMan.computeResForkMD5AsString(0);
- debugPrintf("%s %s (resource)\n", md5.c_str(), macResMan.getBaseFileName().c_str());
+ Common::String md5 = macResMan.computeResForkMD5AsString(length);
+ debugPrintf("%s %s (resource) %d\n", md5.c_str(), macResMan.getBaseFileName().c_str(), macResMan.getResForkDataSize());
}
if (macResMan.hasDataFork()) {
- Common::ReadStream *stream = macResMan.getDataFork();
- Common::String md5 = Common::computeStreamMD5AsString(*stream, 0);
- debugPrintf("%s %s (data)\n", md5.c_str(), macResMan.getBaseFileName().c_str());
+ Common::SeekableReadStream *stream = macResMan.getDataFork();
+ Common::String md5 = Common::computeStreamMD5AsString(*stream, length);
+ debugPrintf("%s %s (data) %d\n", md5.c_str(), macResMan.getBaseFileName().c_str(), stream->size());
}
}
macResMan.close();
diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp
index 339ec95c50..a333c5fe57 100644
--- a/gui/saveload-dialog.cpp
+++ b/gui/saveload-dialog.cpp
@@ -654,16 +654,25 @@ void SaveLoadChooserGrid::open() {
// In case there was a gap found use the slot.
if (lastSlot + 1 < curSlot) {
- _nextFreeSaveSlot = lastSlot + 1;
- break;
+ // Check that the save slot can be used for user saves.
+ SaveStateDescriptor desc = _metaEngine->querySaveMetaInfos(_target.c_str(), lastSlot + 1);
+ if (!desc.getWriteProtectedFlag()) {
+ _nextFreeSaveSlot = lastSlot + 1;
+ break;
+ }
}
lastSlot = curSlot;
}
// Use the next available slot otherwise.
- if (_nextFreeSaveSlot == -1 && lastSlot + 1 < _metaEngine->getMaximumSaveSlot()) {
- _nextFreeSaveSlot = lastSlot + 1;
+ const int maxSlot = _metaEngine->getMaximumSaveSlot();
+ for (int i = lastSlot; _nextFreeSaveSlot == -1 && i < maxSlot; ++i) {
+ // Check that the save slot can be used for user saves.
+ SaveStateDescriptor desc = _metaEngine->querySaveMetaInfos(_target.c_str(), i + 1);
+ if (!desc.getWriteProtectedFlag()) {
+ _nextFreeSaveSlot = i + 1;
+ }
}
}
diff --git a/test/audio/timestamp.h b/test/audio/timestamp.h
index ca56e34a4d..ec42a55ec4 100644
--- a/test/audio/timestamp.h
+++ b/test/audio/timestamp.h
@@ -2,6 +2,8 @@
#include "audio/timestamp.h"
+#include <limits.h>
+
class TimestampTestSuite : public CxxTest::TestSuite
{
public:
@@ -238,4 +240,15 @@ class TimestampTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS(c.numberOfFrames(), 11025);
TS_ASSERT_EQUALS(c.totalNumberOfFrames(), 33075);
}
+
+ void test_no_overflow() {
+ // The constructor should not overflow and give incoherent values
+ const Audio::Timestamp a = Audio::Timestamp(0, UINT_MAX, 1000);
+
+ int secs = UINT_MAX / 1000;
+ int frames = UINT_MAX % 1000;
+
+ TS_ASSERT_EQUALS(a.secs(), secs);
+ TS_ASSERT_EQUALS(a.numberOfFrames(), frames);
+ }
};
diff --git a/video/theora_decoder.h b/video/theora_decoder.h
index b85388426b..feb4c6b49e 100644
--- a/video/theora_decoder.h
+++ b/video/theora_decoder.h
@@ -50,6 +50,7 @@ namespace Video {
*
* Decoder for Theora videos.
* Video decoder used in engines:
+ * - pegasus
* - sword25
* - wintermute
*/
diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp
index dce96aae03..a4bc5b81a2 100644
--- a/video/video_decoder.cpp
+++ b/video/video_decoder.cpp
@@ -530,7 +530,9 @@ Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getFrameTime(uint frame) con
// (which Audio::Timestamp doesn't support).
Common::Rational frameRate = getFrameRate();
- if (frameRate == frameRate.toInt()) // The nice case (a whole number)
+ // Try to keep it in terms of the frame rate, if the frame rate is a whole
+ // number.
+ if (frameRate.getDenominator() == 1)
return Audio::Timestamp(0, frame, frameRate.toInt());
// Convert as best as possible