diff options
Diffstat (limited to 'engines/chewy/video')
-rw-r--r-- | engines/chewy/video/cfo_decoder.cpp | 319 | ||||
-rw-r--r-- | engines/chewy/video/cfo_decoder.h | 74 |
2 files changed, 393 insertions, 0 deletions
diff --git a/engines/chewy/video/cfo_decoder.cpp b/engines/chewy/video/cfo_decoder.cpp new file mode 100644 index 0000000000..0d8fcd7083 --- /dev/null +++ b/engines/chewy/video/cfo_decoder.cpp @@ -0,0 +1,319 @@ +/* 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 "common/events.h" +#include "common/system.h" +#include "engines/engine.h" +#include "graphics/palette.h" +#include "video/flic_decoder.h" + +#include "chewy/sound.h" +#include "chewy/video/cfo_decoder.h" + +namespace Chewy { + +enum CustomSubChunk { + kChunkFadeIn = 0, // unused + kChunkFadeOut = 1, + kChunkLoadMusic = 2, + kChunkLoadRaw = 3, // unused + kChunkLoadVoc = 4, + kChunkPlayMusic = 5, + kChunkPlaySeq = 6, // unused + kChunkPlayPattern = 7, // unused + kChunkStopMusic = 8, + kChunkWaitMusicEnd = 9, + kChunkSetMusicVolume = 10, + kChunkSetLoopMode = 11, // unused + kChunkPlayRaw = 12, // unused + kChunkPlayVoc = 13, + kChunkSetSoundVolume = 14, + kChunkSetChannelVolume = 15, + kChunkFreeSoundEffect = 16, + kChunkMusicFadeIn = 17, // unused + kChunkMusicFadeOut = 18, + kChunkSetBalance = 19, + kChunkSetSpeed = 20, // unused + kChunkClearScreen = 21 +}; + +bool CfoDecoder::loadStream(Common::SeekableReadStream *stream) { + close(); + + if (stream->readUint32BE() != MKTAG('C', 'F', 'O', '\0')) + error("Corrupt video resource"); + + stream->readUint32LE(); // always 0 + + uint16 frameCount = stream->readUint16LE(); + uint16 width = stream->readUint16LE(); + uint16 height = stream->readUint16LE(); + + addTrack(new CfoVideoTrack(stream, frameCount, width, height, _sound)); + return true; +} + +CfoDecoder::CfoVideoTrack::CfoVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, Sound *sound) : + Video::FlicDecoder::FlicVideoTrack(stream, frameCount, width, height, true), _sound(sound) { + readHeader(); + + for (int i = 0; i < MAX_SOUND_EFFECTS; i++) { + _soundEffects[i] = nullptr; + _soundEffectSize[i] = 0; + } + + _musicData = nullptr; + _musicSize = 0; +} + +CfoDecoder::CfoVideoTrack::~CfoVideoTrack() { + _sound->stopAll(); + + for (int i = 0; i < MAX_SOUND_EFFECTS; i++) { + delete[] _soundEffects[i]; + } + + delete[] _musicData; +} + +void CfoDecoder::CfoVideoTrack::readHeader() { + _frameDelay = _startFrameDelay = _fileStream->readUint32LE(); + _offsetFrame1 = _fileStream->readUint32LE(); + _offsetFrame2 = 0; // doesn't exist, as CFO videos aren't rewindable + + _fileStream->seek(_offsetFrame1); +} + +#define FRAME_TYPE 0xF1FA +#define CUSTOM_FRAME_TYPE 0xFAF1 + +const ::Graphics::Surface *CfoDecoder::CfoVideoTrack::decodeNextFrame() { + uint16 frameType; + + // Read chunk + /*uint32 frameSize =*/ _fileStream->readUint32LE(); + frameType = _fileStream->readUint16LE(); + + switch (frameType) { + case FRAME_TYPE: + handleFrame(); + break; + case CUSTOM_FRAME_TYPE: + handleCustomFrame(); + break; + default: + error("CfoDecoder::decodeFrame(): unknown main chunk type (type = 0x%02X)", frameType); + break; + } + + _curFrame++; + _nextFrameStartTime += _frameDelay; + + return _surface; +} + +#define FLI_SETPAL 4 +#define FLI_SS2 7 +#define FLI_BRUN 15 +#define FLI_COPY 16 +#define PSTAMP 18 + +void CfoDecoder::CfoVideoTrack::handleFrame() { + uint16 chunkCount = _fileStream->readUint16LE(); + + // Read subchunks + for (uint32 i = 0; i < chunkCount; ++i) { + uint32 frameSize = _fileStream->readUint32LE(); + uint16 frameType = _fileStream->readUint16LE(); + uint8 *data = new uint8[frameSize - 6]; + _fileStream->read(data, frameSize - 6); + + switch (frameType) { + case FLI_SETPAL: + unpackPalette(data); + _dirtyPalette = true; + break; + case FLI_SS2: + decodeDeltaFLC(data); + break; + case FLI_BRUN: + decodeByteRun(data); + break; + case FLI_COPY: + copyFrame(data); + break; + case PSTAMP: + /* PSTAMP - skip for now */ + break; + default: + error("CfoDecoder::decodeNextFrame(): unknown subchunk type (type = 0x%02X)", frameType); + break; + } + + delete[] data; + } +} + +void CfoDecoder::CfoVideoTrack::handleCustomFrame() { + uint16 chunkCount = _fileStream->readUint16LE(); + + uint16 number, channel, volume, repeat, balance; + + // Read subchunks + for (uint32 i = 0; i < chunkCount; ++i) { + uint32 frameSize = _fileStream->readUint32LE(); + uint16 frameType = _fileStream->readUint16LE(); + + switch (frameType) { + case kChunkFadeIn: + error("Unused chunk kChunkFadeIn found"); + break; + case kChunkFadeOut: + // Used in video 0 + _fileStream->skip(2); // delay, unused + fadeOut(); + break; + case kChunkLoadMusic: + // Used in videos 0, 18, 34, 71 + _musicSize = frameSize; + _musicData = new byte[frameSize]; + _fileStream->read(_musicData, frameSize); + break; + case kChunkLoadRaw: + error("Unused chunk kChunkLoadRaw found"); + break; + case kChunkLoadVoc: + number = _fileStream->readUint16LE(); + assert(number < MAX_SOUND_EFFECTS); + delete[] _soundEffects[number]; + + _soundEffectSize[number] = frameSize - 2; + _soundEffects[number] = new byte[frameSize - 2]; + _fileStream->read(_soundEffects[number], frameSize - 2); + break; + case kChunkPlayMusic: + // Used in videos 0, 18, 34, 71 + _sound->playMusic(_musicData, _musicSize, false, DisposeAfterUse::NO); + break; + case kChunkPlaySeq: + error("Unused chunk kChunkPlaySeq found"); + break; + case kChunkPlayPattern: + error("Unused chunk kChunkPlayPattern found"); + break; + case kChunkStopMusic: + _sound->stopMusic(); + + // Game videos do not restart music after stopping it + delete[] _musicData; + _musicSize = 0; + break; + case kChunkWaitMusicEnd: + do { + Common::Event event; + while (g_system->getEventManager()->pollEvent(event)) {} // ignore events + g_system->updateScreen(); + g_system->delayMillis(10); + } while (_sound->isMusicActive()); + break; + case kChunkSetMusicVolume: + volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; + _sound->setMusicVolume(volume); + break; + case kChunkSetLoopMode: + error("Unused chunk kChunkSetLoopMode found"); + break; + case kChunkPlayRaw: + error("Unused chunk kChunkPlayRaw found"); + break; + case kChunkPlayVoc: + number = _fileStream->readUint16LE(); + channel = _fileStream->readUint16LE(); + volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; + repeat = _fileStream->readUint16LE(); + assert(number < MAX_SOUND_EFFECTS); + + _sound->setSoundVolume(volume); + _sound->playSound(_soundEffects[number], _soundEffectSize[number], repeat, channel, DisposeAfterUse::NO); + break; + case kChunkSetSoundVolume: + volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; + _sound->setSoundVolume(volume); + break; + case kChunkSetChannelVolume: + channel = _fileStream->readUint16LE(); + volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; + + _sound->setSoundChannelVolume(channel, volume); + break; + case kChunkFreeSoundEffect: + number = _fileStream->readUint16LE(); + assert(number < MAX_SOUND_EFFECTS); + + delete[] _soundEffects[number]; + _soundEffects[number] = nullptr; + break; + case kChunkMusicFadeIn: + error("Unused chunk kChunkMusicFadeIn found"); + break; + case kChunkMusicFadeOut: + // Used in videos 0, 71 + warning("kChunkMusicFadeOut"); + // TODO + _fileStream->skip(frameSize); + break; + case kChunkSetBalance: + channel = _fileStream->readUint16LE(); + balance = (_fileStream->readUint16LE() * 2) - 127; + _sound->setSoundChannelBalance(channel, balance); + break; + case kChunkSetSpeed: + error("Unused chunk kChunkSetSpeed found"); + break; + case kChunkClearScreen: + g_system->fillScreen(0); + break; + default: + error("Unknown subchunk: %d", frameType); + break; + } + } +} + +void CfoDecoder::CfoVideoTrack::fadeOut() { + for (int j = 0; j < 64; j++) { + for (int i = 0; i < 256; i++) { + if (_palette[i * 3 + 0] > 0) + --_palette[i * 3 + 0]; + if (_palette[i * 3 + 1] > 0) + --_palette[i * 3 + 1]; + if (_palette[i * 3 + 2] > 0) + --_palette[i * 3 + 2]; + } + + g_system->getPaletteManager()->setPalette(_palette, 0, 256); + g_system->updateScreen(); + g_system->delayMillis(10); + } +} + +} // End of namespace Chewy diff --git a/engines/chewy/video/cfo_decoder.h b/engines/chewy/video/cfo_decoder.h new file mode 100644 index 0000000000..1495821674 --- /dev/null +++ b/engines/chewy/video/cfo_decoder.h @@ -0,0 +1,74 @@ +/* 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. + * + */ + +#ifndef CHEWY_VIDEO_CFO_DECODER_H +#define CHEWY_VIDEO_CFO_DECODER_H + +#include "graphics/surface.h" +#include "video/flic_decoder.h" + +namespace Chewy { + +#define MAX_SOUND_EFFECTS 14 + +class Sound; + +// A FLIC decoder, with a modified header and additional custom frames +class CfoDecoder : public Video::FlicDecoder { +public: + CfoDecoder(Sound *sound) : Video::FlicDecoder(), _sound(sound) {} + virtual ~CfoDecoder() {} + + bool loadStream(Common::SeekableReadStream *stream); + +private: + Sound *_sound; + + class CfoVideoTrack : public Video::FlicDecoder::FlicVideoTrack { + public: + CfoVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, Sound *sound); + virtual ~CfoVideoTrack(); + + void readHeader(); + + bool isRewindable() const { return false; } + bool rewind() { return false; } + + const ::Graphics::Surface *decodeNextFrame(); + + private: + void handleFrame(); + void handleCustomFrame(); + void fadeOut(); + + Sound *_sound; + + byte *_soundEffects[MAX_SOUND_EFFECTS]; + uint32 _soundEffectSize[MAX_SOUND_EFFECTS]; + byte *_musicData; + uint32 _musicSize; + }; +}; + +} // End of namespace Chewy + +#endif |