diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/zvision/rlf_animation.cpp | 230 | ||||
-rw-r--r-- | engines/zvision/rlf_animation.h | 60 |
2 files changed, 290 insertions, 0 deletions
diff --git a/engines/zvision/rlf_animation.cpp b/engines/zvision/rlf_animation.cpp new file mode 100644 index 0000000000..abc31c1d1d --- /dev/null +++ b/engines/zvision/rlf_animation.cpp @@ -0,0 +1,230 @@ +/* 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/scummsys.h" + +#include "common/str.h" +#include "common/file.h" +#include "common/textconsole.h" +#include "common/debug.h" +#include "common/endian.h" + +#include "zvision/rlf_animation.h" + + +namespace ZVision { + +RlfAnimation::RlfAnimation(const Common::String &fileName) + : _frames(0) { + Common::File file; + if (!file.open(fileName)) { + warning("RLF animation file %s could not be opened", fileName.c_str()); + return; + } + + if (file.readUint32BE() != MKTAG('F', 'E', 'L', 'R')) { + warning("%s is not a RLF animation file. Wrong magic number", fileName.c_str()); + return; + } + + // Read the header + file.readUint32LE(); // Size1 + file.readUint32LE(); // Unknown1 + file.readUint32LE(); // Unknown2 + _frameCount = file.readUint32LE(); // Frame count + + // Since we don't need any of the data, we can just seek right to the + // entries we need rather than read in all the individual entries. + file.seek(136, file.pos()); + + //// Read CIN header + //file.readUint32BE(); // Magic number FNIC + //file.readUint32LE(); // Size2 + //file.readUint32LE(); // Unknown3 + //file.readUint32LE(); // Unknown4 + //file.readUint32LE(); // Unknown5 + //file.seek(0x18, file.pos()); // VRLE + //file.readUint32LE(); // LRVD + //file.readUint32LE(); // Unknown6 + //file.seek(0x18, file.pos()); // HRLE + //file.readUint32LE(); // ELHD + //file.readUint32LE(); // Unknown7 + //file.seek(0x18, file.pos()); // HKEY + //file.readUint32LE(); // ELRH + + //// Read MIN info header + //file.readUint32BE(); // Magic number FNIM + //file.readUint32LE(); // Size3 + //file.readUint32LE(); // OEDV + //file.readUint32LE(); // Unknown8 + //file.readUint32LE(); // Unknown9 + //file.readUint32LE(); // Unknown10 + _width = file.readUint32LE(); // Width + _height = file.readUint32LE(); // Height + + // Read time header + file.readUint32BE(); // Magic number EMIT + file.readUint32LE(); // Size4 + file.readUint32LE(); // Unknown11 + _frameTime = file.readUint32LE() / 10; // Frame time in microseconds + + // Read in each frame + _frames = new uint16 *[_frameCount]; + for (uint i = 0; i < _frameCount; i++) { + file.readUint32BE(); // Magic number MARF + uint32 size = file.readUint32LE(); // Size + file.readUint32LE(); // Unknown1 + file.readUint32LE(); // Unknown2 + uint32 type = file.readUint32BE(); // Either ELHD or ELRH + uint32 offset = file.readUint32LE(); // Offset from the beginning of this frame to the frame data. Should always be 28 + file.readUint32LE(); // Unknown3 + + int8 *buffer = new int8[size - headerSize]; + file.read(buffer, size - headerSize); + + _frames[i] = new uint16[_width * _height]; + uint frameByteSize = _width * _height * sizeof(uint16); + memset(_frames[i], 0x7C00, frameByteSize); + // Decode the data + debug("Decoding frame %u", i); + if (type == MKTAG('E', 'L', 'H', 'D')) { + debug("Decoding with masked RLE"); + decodeMaskedRunLengthEncoding(buffer, (int8 *)_frames[i], size - headerSize, frameByteSize); + } else if (type == MKTAG('E', 'L', 'R', 'H')) { + debug("Decoding with simple RLE"); + decodeSimpleRunLengthEncoding(buffer, (int8 *)_frames[i], size - headerSize, frameByteSize); + } else { + warning("Frame %u of %s doesn't have type that can be decoded", i, fileName.c_str()); + return; + } + + // Cleanup + delete[] buffer; + } +}; + +RlfAnimation::~RlfAnimation() { + if (_frames != 0) { + delete[] _frames; + } +} + + + +void RlfAnimation::decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const { + uint32 sourceOffset = 0; + uint32 destOffset = 0; + + while (sourceOffset < sourceSize) { + int8 numberOfSamples = source[sourceOffset]; + sourceOffset++; + + // If numberOfSamples is negative, the next abs(numberOfSamples) samples should + // be copied directly from source to dest + if (numberOfSamples < 0) { + numberOfSamples = abs(numberOfSamples); + + while (numberOfSamples > 0) { + if (sourceOffset + 1 >= sourceSize) { + return; + } else if (destOffset + 1 >= destSize) { + warning("Frame decoding overflow\n\tsourceOffset=%u\tsourceSize=%u\n\tdestOffset=%u\tdestSize=%u", sourceOffset, sourceSize, destOffset, destSize); + return; + } + + WRITE_UINT16(dest + destOffset, READ_LE_UINT16(source + sourceOffset)); + + sourceOffset += 2; + destOffset += 2; + numberOfSamples--; + } + + // If numberOfSamples is >= 0, move destOffset forward ((numberOfSamples * 2) + 2) + // This function assumes the dest buffer has been memset with 0's. + } else { + if (sourceOffset + 1 >= sourceSize) { + return; + } else if (destOffset + 1 >= destSize) { + warning("Frame decoding overflow\n\tsourceOffset=%u\tsourceSize=%u\n\tdestOffset=%u\tdestSize=%u", sourceOffset, sourceSize, destOffset, destSize); + return; + } + + destOffset += (numberOfSamples * 2) + 2; + } + } +} + +void RlfAnimation::decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const { + uint32 sourceOffset = 0; + uint32 destOffset = 0; + + while (sourceOffset < sourceSize) { + int8 numberOfSamples = source[sourceOffset]; + sourceOffset++; + + // If numberOfSamples is negative, the next abs(numberOfSamples) samples should + // be copied directly from source to dest + if (numberOfSamples < 0) { + numberOfSamples = abs(numberOfSamples); + + while (numberOfSamples > 0) { + if (sourceOffset + 1 >= sourceSize) { + return; + } else if (destOffset + 1 >= destSize) { + warning("Frame decoding overflow\n\tsourceOffset=%u\tsourceSize=%u\n\tdestOffset=%u\tdestSize=%u", sourceOffset, sourceSize, destOffset, destSize); + return; + } + + WRITE_UINT16(dest + destOffset, READ_LE_UINT16(source + sourceOffset)); + + sourceOffset += 2; + destOffset += 2; + numberOfSamples--; + } + + // If numberOfSamples is >= 0, copy one sample from source to the + // next (numberOfSamples + 2) dest spots + } else { + if (sourceOffset + 1 >= sourceSize) { + return; + } + + uint16 sampleColor = READ_LE_UINT16(source + sourceOffset); + sourceOffset += 2; + + numberOfSamples += 2; + while (numberOfSamples > 0) { + if (destOffset + 1 >= destSize) { + warning("Frame decoding overflow\n\tsourceOffset=%u\tsourceSize=%u\n\tdestOffset=%u\tdestSize=%u", sourceOffset, sourceSize, destOffset, destSize); + return; + } + + WRITE_UINT16(dest + destOffset, sampleColor); + destOffset += 2; + numberOfSamples--; + } + } + } +} + + +} // End of namespace ZVision diff --git a/engines/zvision/rlf_animation.h b/engines/zvision/rlf_animation.h new file mode 100644 index 0000000000..7ece4e5063 --- /dev/null +++ b/engines/zvision/rlf_animation.h @@ -0,0 +1,60 @@ +/* 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 ZVISION_RLF_ANIMATION_H +#define ZVISION_RLF_ANIMATION_H + + +namespace Common { +class String; +} + +namespace ZVision { + +class RlfAnimation { +public: + RlfAnimation(const Common::String &fileName); + ~RlfAnimation(); + +private: +private: + uint _frameCount; + uint _width; + uint _height; + uint32 _frameTime; // In milliseconds + uint16 **_frames; + +public: + uint frameCount() { return _frameCount; } + uint width() { return _width; } + uint height() { return _height; } + uint32 frameTime() { return _frameTime; } + const uint16 *getFrameData(uint frameNumber) const { return _frames[frameNumber]; } + +private: + void decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const; + void decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const; +}; + +} // End of namespace ZVision + +#endif |