diff options
Diffstat (limited to 'engines/supernova/graphics.cpp')
-rw-r--r-- | engines/supernova/graphics.cpp | 157 |
1 files changed, 154 insertions, 3 deletions
diff --git a/engines/supernova/graphics.cpp b/engines/supernova/graphics.cpp index 1daa94b42d..e2467d1c3c 100644 --- a/engines/supernova/graphics.cpp +++ b/engines/supernova/graphics.cpp @@ -1,11 +1,162 @@ +#include "common/algorithm.h" +#include "common/file.h" +#include "common/stream.h" +#include "common/system.h" +#include "graphics/palette.h" +#include "graphics/surface.h" + #include "graphics.h" +namespace Supernova { + MSNImageDecoder::MSNImageDecoder() -{ + : _surface(NULL) + , _palette(NULL) { +} +MSNImageDecoder::~MSNImageDecoder() { + destroy(); } -MSNImageDecoder::~MSNImageDecoder() -{ +bool MSNImageDecoder::loadStream(Common::SeekableReadStream &stream) { + destroy(); + + size_t size = 0; + size = (stream.readUint16LE() + 0xF) >> 4; + size |= (stream.readUint16LE() & 0xF) << 12; + size += 0x70; // zus_paragraph + size *= 16; // a paragraph is 16 bytes + _encodedImage = new byte[size]; + + _palette = new byte[768]; + g_system->getPaletteManager()->grabPalette(_palette, 0, 256); + + byte pal_diff; + byte flag = stream.readByte(); + if (flag == 0) { + pal_diff = 0; + _palette[141] = 0x38; + _palette[142] = 0x38; + _palette[143] = 0x38; + } else { + pal_diff = 1; + for (int i = flag * 3; i != 0; --i) { + _palette[717 - i] = stream.readByte(); + } + } + g_system->getPaletteManager()->setPalette(_palette, 0, 256); + + byte numSections = stream.readByte(); + for (size_t i = 0; i < kMaxSections; ++i) { + _section[i].addressHigh = 0xff; + _section[i].addressLow = 0xffff; + _section[i].x2 = 0; + } + for (int i = 0; i < numSections; ++i) { + _section[i].x1 = stream.readUint16LE(); + _section[i].x2 = stream.readUint16LE(); + _section[i].y1 = stream.readByte(); + _section[i].y2 = stream.readByte(); + _section[i].next = stream.readByte(); + _section[i].addressLow = stream.readUint16LE(); + _section[i].addressHigh = stream.readByte(); + } + + byte numClickFields = stream.readByte(); + for (int i = 0; i < numClickFields; ++i) { + _clickField[i].x1 = stream.readUint16LE(); + _clickField[i].x2 = stream.readUint16LE(); + _clickField[i].y1 = stream.readByte(); + _clickField[i].y2 = stream.readByte(); + _clickField[i].next = stream.readByte(); + } + + byte zwCodes[256]; + byte numRepeat = stream.readByte(); + byte numZw = stream.readByte(); + stream.read(zwCodes, numZw); + numZw += numRepeat; + + byte input = 0; + size_t i = 0; + // wat + while (stream.read(&input, 1)) { + if (input < numRepeat) { + ++input; + byte value = stream.readByte(); + for (--value; input > 0; --input) { + _encodedImage[i++] = value; + } + } else if (input < numZw) { + input = zwCodes[input]; + --input; + _encodedImage[i++] = input; + _encodedImage[i++] = input; + } else { + input -= pal_diff; + _encodedImage[i++] = input; + } + } + return true; +} + +bool MSNImageDecoder::loadSection(int section) { + _surface = new Graphics::Surface; + _surface->create(320, 200, g_system->getScreenFormat()); + byte *surfacePixels = static_cast<byte *>(_surface->getPixels()); + + const uint32 kInvalidAddress = 0x00FFFFFF; + + size_t image = section; + if (image < 128) { + do { + uint32 offset = (_section[image].addressHigh << 16) + _section[image].addressLow; + if (offset == kInvalidAddress) { + return false; + } + int width = _section[image].x2 - _section[image].x1 + 1; + int height = _section[image].y2 - _section[image].y1 + 1; + uint32 destAddress = 320 * _section[image].y1 + _section[image].x1; + while (height) { + Common::copy(_encodedImage + offset, _encodedImage + offset + width, surfacePixels + destAddress); + offset += width; + destAddress += 320; + --height; + } + + image = _section[image].next; + } while (image != 0); + } else { + image -= 128; + do { + int width = _section[image].x2 - _section[image].x1 + 1; + int height = _section[image].y2 - _section[image].y1 + 1; + uint32 destAddress = 320 * _section[image].y1 + _section[image].x1; + uint32 offset = (_section[image].addressHigh << 16) + _section[image].addressLow + destAddress; + while (height) { + Common::copy(_encodedImage + offset, _encodedImage + offset + width, surfacePixels + destAddress); + offset += 320; + destAddress += 320; + --height; + } + + image = _section[image].next; + } while (image != 0); + } + + return true; +} + +void MSNImageDecoder::destroy() { + if (_palette) { + delete[] _palette; + _palette = NULL; + } + if (_surface) { + _surface->free(); + _surface = NULL; + } +} + } |