diff options
author | Ľubomír Remák | 2018-03-25 20:33:42 +0200 |
---|---|---|
committer | Eugene Sandulenko | 2018-08-25 23:12:01 +0200 |
commit | 2b94873694619272f79f6b358d4a18c8bce13cd8 (patch) | |
tree | acdd870907feca5f65eba261e717d598d7770fae /engines/mutationofjb | |
parent | 128d30c91c114d771e7777963716d3625be8cfeb (diff) | |
download | scummvm-rg350-2b94873694619272f79f6b358d4a18c8bce13cd8.tar.gz scummvm-rg350-2b94873694619272f79f6b358d4a18c8bce13cd8.tar.bz2 scummvm-rg350-2b94873694619272f79f6b358d4a18c8bce13cd8.zip |
MUTATIONOFJB: Introduce better animation loader that supports diff frames.
Diffstat (limited to 'engines/mutationofjb')
-rw-r--r-- | engines/mutationofjb/animationdecoder.cpp | 191 | ||||
-rw-r--r-- | engines/mutationofjb/animationdecoder.h | 69 | ||||
-rw-r--r-- | engines/mutationofjb/module.mk | 1 | ||||
-rw-r--r-- | engines/mutationofjb/room.cpp | 123 | ||||
-rw-r--r-- | engines/mutationofjb/room.h | 5 |
5 files changed, 285 insertions, 104 deletions
diff --git a/engines/mutationofjb/animationdecoder.cpp b/engines/mutationofjb/animationdecoder.cpp new file mode 100644 index 0000000000..585ad91aa8 --- /dev/null +++ b/engines/mutationofjb/animationdecoder.cpp @@ -0,0 +1,191 @@ +/* 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 "mutationofjb/animationdecoder.h" +#include "mutationofjb/encryptedfile.h" +#include "mutationofjb/util.h" +#include "common/debug.h" +#include "common/translation.h" + +namespace MutationOfJB { + +AnimationDecoder::AnimationDecoder(const Common::String &fileName) : _fileName(fileName) { + _surface.create(IMAGE_WIDTH, IMAGE_HEIGHT, Graphics::PixelFormat::createFormatCLUT8()); +} + +bool AnimationDecoder::decode(AnimationDecoderCallback *callback) { + EncryptedFile file; + file.open(_fileName); + + if (!file.isOpen()) { + reportFileMissingError(_fileName.c_str()); + + return false; + } + + file.seek(0, SEEK_END); + const int32 endPos = file.pos(); + + // Skip header - we don't need it anyway. + file.seek(0x80); + + int frameNo = 0; + + while (file.pos() != endPos) { + // Record. + const uint32 length = file.readUint32LE(); + const uint16 recordId = file.readUint16LE(); + const uint16 subrecords = file.readUint16LE(); + + // Skip 8 empty bytes. + file.seek(8, SEEK_CUR); + + // Subrecords. + if (recordId == 0xF1FA) { + for (int i = 0; i < subrecords; ++i) { + int32 filePos = file.pos(); + + const uint32 subLength = file.readUint32LE(); + const uint16 type = file.readUint16LE(); + + if (type == 0x0B) { + loadPalette(file); + if (callback) { + callback->onPaletteUpdated(_palette); + } + } else if (type == 0x0F) { + loadFullFrame(file, subLength - 6); + if (callback) { + callback->onFrame(frameNo, _surface); + } + } else if (type == 0x0C) { + loadDiffFrame(file, subLength - 6); + if (callback) { + callback->onFrame(frameNo, _surface); + } + } else { + debug(_("Unsupported record type %02X."), type); + file.seek(subLength - 6, SEEK_CUR); + } + + // Makes decoding more robust, because for some reason records might have extra data at the end. + file.seek(filePos + subLength, SEEK_SET); + } + frameNo++; + } else { + file.seek(length - 16, SEEK_CUR); + } + } + file.close(); + + return true; +} + +void AnimationDecoder::loadPalette(Common::SeekableReadStream &file) { + uint16 packets = file.readUint16LE(); + const uint8 skipCount = file.readByte(); + int copyCount = file.readByte(); + if (copyCount == 0) { + copyCount = PALETTE_COLORS; + } + + while(packets--) { + file.read(_palette + skipCount * 3, copyCount * 3); + + for (int j = skipCount * 3; j < (skipCount + copyCount) * 3; ++j) { + _palette[j] <<= 2; // Uses 6-bit colors. + } + } +} + +void AnimationDecoder::loadFullFrame(EncryptedFile &file, uint32 size) { + uint8 *const pixels = reinterpret_cast<uint8 *>(_surface.getPixels()); + uint8 *ptr = pixels; + uint32 readBytes = 0; + uint32 lines = 0; + + while (readBytes != size) { + if (lines == 200) { + // Some full frames have an unknown byte at the end, + // so break when we encounter all 200 lines. + break; + } + + uint8 no = file.readByte(); + readBytes++; + while (no--) { + uint8 n = file.readByte(); + readBytes++; + if (n < 0x80) { + // RLE - Copy color n times. + uint8 color = file.readByte(); + readBytes++; + while(n--) { + *ptr++ = color; + } + } else { + // Take next 0x100 - n bytes as they are. + const uint32 rawlen = 0x100 - n; + file.read(ptr, rawlen); + readBytes += rawlen; + ptr += rawlen; + } + } + lines++; + } +} + +void AnimationDecoder::loadDiffFrame(EncryptedFile &file, uint32) { + const uint16 firstLine = file.readUint16LE(); + const uint16 numLines = file.readUint16LE(); + + for (uint16 line = firstLine; line < firstLine + numLines; ++line) { + uint8 *imageData = reinterpret_cast<uint8 *>(_surface.getBasePtr(0, firstLine)); + + uint8 runs = file.readByte(); + while (runs--) { + uint8 localOffset = file.readByte(); + uint8 num = file.readByte(); + + imageData += localOffset; + if (num == 0) { + // Ignore? + debug("Zero RLE number found."); + } else if (num < 0x80) { + file.read(imageData, num); + imageData += num; + } else { + const uint8 color = file.readByte(); + const int no = 0x100 - num; + memset(imageData, color, no); + imageData += no; + } + + } + } +} + +AnimationDecoder::~AnimationDecoder() { + _surface.free(); +} + +} diff --git a/engines/mutationofjb/animationdecoder.h b/engines/mutationofjb/animationdecoder.h new file mode 100644 index 0000000000..050aa3b9dd --- /dev/null +++ b/engines/mutationofjb/animationdecoder.h @@ -0,0 +1,69 @@ +/* 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 MUTATIONOFJB_ANIMATIONDECODER_H +#define MUTATIONOFJB_ANIMATIONDECODER_H + +#include "common/scummsys.h" +#include "common/str.h" +#include "graphics/surface.h" +#include "mutationofjb/encryptedfile.h" + +namespace Common { +class SeekableReadStream; +} + +namespace MutationOfJB { + +enum { + PALETTE_COLORS = 256, + PALETTE_SIZE = PALETTE_COLORS * 3, + IMAGE_WIDTH = 320, + IMAGE_HEIGHT = 200 +}; + +class AnimationDecoderCallback { +public: + virtual void onFrame(int frameNo, Graphics::Surface &surface) = 0; + virtual void onPaletteUpdated(byte palette[PALETTE_SIZE]) = 0; + virtual ~AnimationDecoderCallback() {} +}; + +class AnimationDecoder { +public: + AnimationDecoder(const Common::String &fileName); + ~AnimationDecoder(); + bool decode(AnimationDecoderCallback *callback); + +private: + void loadPalette(Common::SeekableReadStream &stream); + void loadFullFrame(EncryptedFile &file, uint32 size); + void loadDiffFrame(EncryptedFile &file, uint32 size); + + Common::String _fileName; + Graphics::Surface _surface; + byte _palette[PALETTE_SIZE]; +}; + +} + +#endif diff --git a/engines/mutationofjb/module.mk b/engines/mutationofjb/module.mk index 917ab3c4c7..b7966988a5 100644 --- a/engines/mutationofjb/module.mk +++ b/engines/mutationofjb/module.mk @@ -18,6 +18,7 @@ MODULE_OBJS := \ commands/removeitemcommand.o \ commands/saycommand.o \ commands/seqcommand.o \ + animationdecoder.o \ debug.o \ detection.o \ encryptedfile.o \ diff --git a/engines/mutationofjb/room.cpp b/engines/mutationofjb/room.cpp index 8d8fbdbafb..547cda43f4 100644 --- a/engines/mutationofjb/room.cpp +++ b/engines/mutationofjb/room.cpp @@ -21,6 +21,7 @@ */ #include "mutationofjb/room.h" +#include "mutationofjb/animationdecoder.h" #include "mutationofjb/encryptedfile.h" #include "mutationofjb/util.h" #include "common/str.h" @@ -29,114 +30,34 @@ namespace MutationOfJB { -Room::Room(Graphics::Screen *screen) : _screen(screen) {} - -bool Room::load(uint8 roomNumber, bool roomB) { - EncryptedFile file; - Common::String fileName = Common::String::format("room%d%s.dat", roomNumber, roomB ? "b" : ""); - - file.open(fileName); - - if (!file.isOpen()) { - reportFileMissingError(fileName.c_str()); - - return false; - } - - file.seek(0x80); - - while (!file.eos()) { - // Record. - const uint32 length = file.readUint32LE(); - uint8 info[4] = {0}; - file.read(info, 4); - - // TODO Find out what these are. - uint32 unknown; - unknown = file.readUint32LE(); - unknown = file.readUint32LE(); - - // Subrecords. - if (info[0] == 0xFA && info[1] == 0xF1) { - for (int i = 0; i < info[2]; ++i) { - const uint32 subLength = file.readUint32LE(); - const uint16 type = file.readUint16LE(); - - if (type == 0x0B) { - loadPalette(file); - } else if (type == 0x0F) { - loadBackground(file, subLength - 6); - } else { - debug(_("Unsupported record type %02X."), type); - file.seek(subLength - 6, SEEK_CUR); - } - } - } - } - - file.close(); - - return true; +class RoomAnimationDecoderCallback : public AnimationDecoderCallback { +public: + RoomAnimationDecoderCallback(Room &room) : _room(room) {} + virtual void onFrame(int frameNo, Graphics::Surface &surface) override; + virtual void onPaletteUpdated(byte palette[PALETTE_SIZE]) override; +private: + Room &_room; +}; + +void RoomAnimationDecoderCallback::onPaletteUpdated(byte palette[PALETTE_SIZE]) { + _room._screen->setPalette(palette, 0x00, 0xC0); // Load only 0xC0 colors. } -void Room::loadPalette(EncryptedFile &file) { - uint32 unknown; - - // TODO Find out what this is. - unknown = file.readUint32LE(); - - uint8 palette[PALETTE_SIZE]; - file.read(palette, PALETTE_SIZE); - - for (int j = 0; j < PALETTE_SIZE; ++j) { - palette[j] <<= 2; // Uses 6-bit colors. +void RoomAnimationDecoderCallback::onFrame(int frameNo, Graphics::Surface &surface) { + if (frameNo != 0) { + return; } - _screen->setPalette(palette, 0x00, 0xC0); // Load only 0xC0 colors. + _room._screen->blitFrom(surface); } -void Room::loadBackground(EncryptedFile &file, uint32 size) { - _screen->clear(); - - uint8 *const pixels = static_cast<uint8 *>(_screen->getPixels()); - uint8 *ptr = pixels; - uint32 readBytes = 0; - uint32 lines = 0; - - while (readBytes != size) { - if (lines == 200) { - // Some background files have an unknown byte at the end, - // so break when we encounter all 200 lines. - break; - } - - uint8 no = file.readByte(); - readBytes++; - while (no--) { - uint8 n = file.readByte(); - readBytes++; - if (n < 0x80) { - // RLE - Copy color n times. - uint8 color = file.readByte(); - readBytes++; - while(n--) { - *ptr++ = color; - } - } else { - // Take next 0x100 - n bytes as they are. - const uint32 rawlen = 0x100 - n; - file.read(ptr, rawlen); - readBytes += rawlen; - ptr += rawlen; - } - } - lines++; - } - if (readBytes < size) { - file.seek(size - readBytes, SEEK_CUR); - } +Room::Room(Graphics::Screen *screen) : _screen(screen) {} - _screen->update(); +bool Room::load(uint8 roomNumber, bool roomB) { + const Common::String fileName = Common::String::format("room%d%s.dat", roomNumber, roomB ? "b" : ""); + AnimationDecoder decoder(fileName); + RoomAnimationDecoderCallback callback(*this); + return decoder.decode(&callback); } } diff --git a/engines/mutationofjb/room.h b/engines/mutationofjb/room.h index 7158580831..e8f444007e 100644 --- a/engines/mutationofjb/room.h +++ b/engines/mutationofjb/room.h @@ -35,12 +35,11 @@ class EncryptedFile; class Room { public: + friend class RoomAnimationDecoderCallback; + Room(Graphics::Screen *screen); bool load(uint8 roomNumber, bool roomB); private: - void loadPalette(EncryptedFile &file); - void loadBackground(EncryptedFile &file, uint32 size); - Graphics::Screen *_screen; }; |