aboutsummaryrefslogtreecommitdiff
path: root/engines/sherlock/animation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sherlock/animation.cpp')
-rw-r--r--engines/sherlock/animation.cpp324
1 files changed, 324 insertions, 0 deletions
diff --git a/engines/sherlock/animation.cpp b/engines/sherlock/animation.cpp
new file mode 100644
index 0000000000..bbf7c913b7
--- /dev/null
+++ b/engines/sherlock/animation.cpp
@@ -0,0 +1,324 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "sherlock/animation.h"
+#include "sherlock/sherlock.h"
+#include "common/algorithm.h"
+
+namespace Sherlock {
+
+static const int NO_FRAMES = FRAMES_END;
+
+Animation::Animation(SherlockEngine *vm) : _vm(vm) {
+}
+
+bool Animation::play(const Common::String &filename, bool intro, int minDelay, int fade,
+ bool setPalette, int speed) {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ Sound &sound = *_vm->_sound;
+ int soundNumber = 0;
+
+ // Check for any any sound frames for the given animation
+ const int *soundFrames = checkForSoundFrames(filename, intro);
+
+ // Add on the VDX extension
+ Common::String vdxName = filename + ".vdx";
+
+ // Load the animation
+ Common::SeekableReadStream *stream;
+ if (!_gfxLibraryFilename.empty())
+ stream = _vm->_res->load(vdxName, _gfxLibraryFilename);
+ else if (_vm->_useEpilogue2)
+ stream = _vm->_res->load(vdxName, "epilog2.lib");
+ else
+ stream = _vm->_res->load(vdxName, "epilogue.lib");
+
+ // Load initial image
+ Common::String vdaName = filename + ".vda";
+ ImageFile images(vdaName, true, true);
+
+ events.wait(minDelay);
+ if (fade != 0 && fade != 255)
+ screen.fadeToBlack();
+
+ if (setPalette) {
+ if (fade != 255)
+ screen.setPalette(images._palette);
+ }
+
+ int frameNumber = 0;
+ Common::Point pt;
+ bool skipped = false;
+ while (!_vm->shouldQuit()) {
+ // Get the next sprite to display
+ int imageFrame = stream->readSint16LE();
+
+ if (imageFrame == -2) {
+ // End of animation reached
+ break;
+ } else if (imageFrame != -1) {
+ // Read position from either animation stream or the sprite frame itself
+ if (imageFrame < 0) {
+ imageFrame += 32768;
+ pt.x = stream->readUint16LE();
+ pt.y = stream->readUint16LE();
+ } else {
+ pt = images[imageFrame]._offset;
+ }
+
+ // Draw the sprite. Note that we explicitly use the raw frame below, rather than the ImageFrame,
+ // since we don't want the offsets in the image file to be used, just the explicit position we specify
+ screen.transBlitFrom(images[imageFrame]._frame, pt);
+ } else {
+ // At this point, either the sprites for the frame has been complete, or there weren't any sprites
+ // at all to draw for the frame
+ if (fade == 255) {
+ // Gradual fade in
+ if (screen.equalizePalette(images._palette) == 0)
+ fade = 0;
+ }
+
+ // Check if we've reached a frame with sound
+ if (frameNumber++ == *soundFrames) {
+ ++soundNumber;
+ ++soundFrames;
+
+ Common::String sampleFilename;
+
+ if (!intro) {
+ // regular animation, append 1-digit number
+ sampleFilename = Common::String::format("%s%01d", filename.c_str(), soundNumber);
+ } else {
+ // intro animation, append 2-digit number
+ sampleFilename = Common::String::format("%s%02d", filename.c_str(), soundNumber);
+ }
+
+ if (sound._voices)
+ sound.playSound(sampleFilename, WAIT_RETURN_IMMEDIATELY, 100, _soundLibraryFilename.c_str());
+ }
+
+ events.wait(speed * 3);
+ }
+
+ if (events.kbHit()) {
+ Common::KeyState keyState = events.getKey();
+ if (keyState.keycode == Common::KEYCODE_ESCAPE ||
+ keyState.keycode == Common::KEYCODE_SPACE) {
+ skipped = true;
+ break;
+ }
+ } else if (events._pressed) {
+ skipped = true;
+ break;
+ }
+ }
+
+ events.clearEvents();
+ sound.stopSound();
+ delete stream;
+
+ return !skipped && !_vm->shouldQuit();
+}
+
+bool Animation::play3DO(const Common::String &filename, bool intro, int minDelay, bool fadeFromGrey,
+ int speed) {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ Sound &sound = *_vm->_sound;
+ int soundNumber = 0;
+
+ bool fadeActive = false;
+ uint16 fadeLimitColor = 0;
+ uint16 fadeLimitColorRed = 0;
+ uint16 fadeLimitColorGreen = 0;
+ uint16 fadeLimitColorBlue = 0;
+
+ // Check for any any sound frames for the given animation
+ const int *soundFrames = checkForSoundFrames(filename, intro);
+
+ // Add the VDX extension
+ Common::String indexName = "prologue/" + filename + ".3dx";
+
+ // Load the animation
+ Common::File *indexStream = new Common::File();
+
+ if (!indexStream->open(indexName)) {
+ warning("unable to open %s\n", indexName.c_str());
+ return false;
+ }
+
+ // Load initial image
+ Common::String graphicsName = "prologue/" + filename + ".3da";
+ ImageFile3DO images(graphicsName, kImageFile3DOType_Animation);
+
+ events.wait(minDelay);
+
+ if (fadeFromGrey) {
+ fadeActive = true;
+ fadeLimitColor = 0xCE59; // RGB565: 25, 50, 25 -> "grey"
+ }
+
+ int frameNumber = 0;
+ Common::Point pt;
+ bool skipped = false;
+ while (!_vm->shouldQuit()) {
+ // Get the next sprite to display
+ int imageFrame = indexStream->readSint16BE();
+
+ if (imageFrame == -2) {
+ // End of animation reached
+ break;
+ } else if (imageFrame != -1) {
+ // Read position from either animation stream or the sprite frame itself
+ if (imageFrame < 0) {
+ imageFrame += 32768;
+ pt.x = indexStream->readUint16BE();
+ pt.y = indexStream->readUint16BE();
+ } else {
+ pt = images[imageFrame]._offset;
+ }
+
+ // Draw the sprite. Note that we explicitly use the raw frame below, rather than the ImageFrame,
+ // since we don't want the offsets in the image file to be used, just the explicit position we specify
+ if (!fadeActive) {
+ screen.transBlitFrom(images[imageFrame]._frame, pt);
+ } else {
+ // Fade active, blit to backbuffer1
+ screen._backBuffer1.transBlitFrom(images[imageFrame]._frame, pt);
+ }
+ } else {
+ // At this point, either the sprites for the frame has been complete, or there weren't any sprites
+ // at all to draw for the frame
+
+ if (fadeActive) {
+ // process fading
+ screen.blitFrom3DOcolorLimit(fadeLimitColor);
+
+ if (!fadeLimitColor) {
+ // we are at the end, so stop
+ fadeActive = false;
+ } else {
+ // decrease limit color
+ fadeLimitColorRed = fadeLimitColor & 0xF800;
+ fadeLimitColorGreen = fadeLimitColor & 0x07E0;
+ fadeLimitColorBlue = fadeLimitColor & 0x001F;
+ if (fadeLimitColorRed)
+ fadeLimitColor -= 0x0800;
+ if (fadeLimitColorGreen)
+ fadeLimitColor -= 0x0040; // -2 because we are using RGB565, sherlock uses RGB555
+ if (fadeLimitColorBlue)
+ fadeLimitColor -= 0x0001;
+ }
+ }
+
+ // Check if we've reached a frame with sound
+ if (frameNumber++ == *soundFrames) {
+ ++soundNumber;
+ ++soundFrames;
+
+ Common::String sampleFilename;
+
+ // append 1-digit number
+ sampleFilename = Common::String::format("prologue/sounds/%s%01d", filename.c_str(), soundNumber);
+
+ if (sound._voices)
+ sound.playSound(sampleFilename, WAIT_RETURN_IMMEDIATELY, 100); // no sound library
+ }
+ events.wait(speed * 3);
+ }
+
+ if (events.kbHit()) {
+ Common::KeyState keyState = events.getKey();
+ if (keyState.keycode == Common::KEYCODE_ESCAPE ||
+ keyState.keycode == Common::KEYCODE_SPACE) {
+ skipped = true;
+ break;
+ }
+ } else if (events._pressed) {
+ skipped = true;
+ break;
+ }
+ }
+
+ events.clearEvents();
+ sound.stopSound();
+ delete indexStream;
+
+ return !skipped && !_vm->shouldQuit();
+}
+
+void Animation::setPrologueNames(const char *const *names, int count) {
+ for (int idx = 0; idx < count; ++idx, ++names) {
+ _prologueNames.push_back(*names);
+ }
+}
+
+void Animation::setPrologueFrames(const int *frames, int count, int maxFrames) {
+ _prologueFrames.resize(count);
+
+ for (int idx = 0; idx < count; ++idx, frames += maxFrames) {
+ _prologueFrames[idx].resize(maxFrames);
+ Common::copy(frames, frames + maxFrames, &_prologueFrames[idx][0]);
+ }
+}
+
+void Animation::setTitleNames(const char *const *names, int count) {
+ for (int idx = 0; idx < count; ++idx, ++names) {
+ _titleNames.push_back(*names);
+ }
+}
+
+void Animation::setTitleFrames(const int *frames, int count, int maxFrames) {
+ _titleFrames.resize(count);
+
+ for (int idx = 0; idx < count; ++idx, frames += maxFrames) {
+ _titleFrames[idx].resize(maxFrames);
+ Common::copy(frames, frames + maxFrames, &_titleFrames[idx][0]);
+ }
+}
+
+const int *Animation::checkForSoundFrames(const Common::String &filename, bool intro) {
+ const int *frames = &NO_FRAMES;
+
+ if (!intro) {
+ // regular animation is playing
+ for (uint idx = 0; idx < _prologueNames.size(); ++idx) {
+ if (filename.equalsIgnoreCase(_prologueNames[idx])) {
+ frames = &_prologueFrames[idx][0];
+ break;
+ }
+ }
+ } else {
+ // intro-animation is playing
+ for (uint idx = 0; idx < _titleNames.size(); ++idx) {
+ if (filename.equalsIgnoreCase(_titleNames[idx])) {
+ frames = &_titleFrames[idx][0];
+ break;
+ }
+ }
+ }
+
+ return frames;
+}
+
+} // End of namespace Sherlock