Initial commit
This commit is contained in:
345
engines/sherlock/animation.cpp
Normal file
345
engines/sherlock/animation.cpp
Normal file
@@ -0,0 +1,345 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sherlock/animation.h"
|
||||
#include "sherlock/sherlock.h"
|
||||
#include "sherlock/scalpel/scalpel_screen.h"
|
||||
#include "sherlock/scalpel/3do/scalpel_3do_screen.h"
|
||||
|
||||
#include "common/algorithm.h"
|
||||
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
static const int NO_FRAMES = FRAMES_END;
|
||||
|
||||
Animation::Animation(SherlockEngine *vm) : _vm(vm) {
|
||||
}
|
||||
|
||||
bool Animation::play(const Common::Path &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::Path vdxName(filename);
|
||||
vdxName.appendInPlace(".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::Path vdaName(filename);
|
||||
vdaName.appendInPlace(".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);
|
||||
}
|
||||
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
keymapper->disableAllGameKeymaps();
|
||||
keymapper->getKeymap("animation")->setEnabled(true);
|
||||
|
||||
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.SHtransBlitFrom(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::Path sampleFilename;
|
||||
|
||||
if (!intro) {
|
||||
// regular animation, append 1-digit number
|
||||
sampleFilename = filename.append(Common::String::format("%01d", soundNumber));
|
||||
} else {
|
||||
// intro animation, append 2-digit number
|
||||
sampleFilename = filename.append(Common::String::format("%02d", soundNumber));
|
||||
}
|
||||
|
||||
if (sound._voices)
|
||||
sound.playSound(sampleFilename, WAIT_RETURN_IMMEDIATELY, 100, _soundLibraryFilename);
|
||||
}
|
||||
|
||||
events.wait(speed * 3);
|
||||
}
|
||||
|
||||
if (events.actionHit()) {
|
||||
Common::CustomEventType action = events.getAction();
|
||||
if (action == kActionSkipAnim) {
|
||||
skipped = true;
|
||||
break;
|
||||
}
|
||||
} else if (events._pressed) {
|
||||
skipped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
keymapper->getKeymap("animation")->setEnabled(false);
|
||||
keymapper->getKeymap("sherlock-default")->setEnabled(true);
|
||||
keymapper->getKeymap("scalpel")->setEnabled(true);
|
||||
keymapper->getKeymap("scalpel-quit")->setEnabled(true);
|
||||
|
||||
events.clearEvents();
|
||||
sound.stopSound();
|
||||
delete stream;
|
||||
|
||||
return !skipped && !_vm->shouldQuit();
|
||||
}
|
||||
|
||||
bool Animation::play3DO(const Common::Path &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::Path indexName("prologue/");
|
||||
indexName.appendInPlace(filename);
|
||||
indexName.appendInPlace(".3dx");
|
||||
|
||||
// Load the animation
|
||||
Common::File indexStream;
|
||||
if (!indexStream.open(indexName)) {
|
||||
warning("unable to open %s\n", indexName.toString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load initial image
|
||||
Common::Path graphicsName("prologue/");
|
||||
graphicsName.appendInPlace(filename);
|
||||
graphicsName.appendInPlace(".3da");
|
||||
ImageFile3DO images(graphicsName, kImageFile3DOType_Animation);
|
||||
|
||||
events.wait(minDelay);
|
||||
|
||||
if (fadeFromGrey) {
|
||||
fadeActive = true;
|
||||
fadeLimitColor = 0xCE59; // RGB565: 25, 50, 25 -> "grey"
|
||||
}
|
||||
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
keymapper->disableAllGameKeymaps();
|
||||
keymapper->getKeymap("animation")->setEnabled(true);
|
||||
|
||||
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
|
||||
screen._backBuffer1.SHtransBlitFrom(images[imageFrame]._frame, pt);
|
||||
if (!fadeActive)
|
||||
screen.slamArea(pt.x, pt.y, images[imageFrame]._frame.w, images[imageFrame]._frame.h);
|
||||
} 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
|
||||
static_cast<Scalpel::Scalpel3DOScreen *>(_vm->_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;
|
||||
|
||||
// append 1-digit number
|
||||
Common::Path sampleFilename("prologue/sounds/");
|
||||
sampleFilename.appendInPlace(filename);
|
||||
sampleFilename.appendInPlace(Common::String::format("%01d", soundNumber));
|
||||
|
||||
if (sound._voices)
|
||||
sound.playSound(sampleFilename, WAIT_RETURN_IMMEDIATELY, 100); // no sound library
|
||||
}
|
||||
events.wait(speed * 3);
|
||||
}
|
||||
|
||||
if (events.actionHit()) {
|
||||
Common::CustomEventType action = events.getAction();
|
||||
if (action == kActionSkipAnim) {
|
||||
skipped = true;
|
||||
break;
|
||||
}
|
||||
} else if (events._pressed) {
|
||||
skipped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
keymapper->getKeymap("animation")->setEnabled(false);
|
||||
keymapper->getKeymap("sherlock-default")->setEnabled(true);
|
||||
keymapper->getKeymap("scalpel")->setEnabled(true);
|
||||
keymapper->getKeymap("scalpel-quit")->setEnabled(true);
|
||||
|
||||
events.clearEvents();
|
||||
sound.stopSound();
|
||||
|
||||
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::Path &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
|
||||
Reference in New Issue
Block a user