Skip to content

Commit

Permalink
SHERLOCK: RT: Properly implement StreamingImageFile class
Browse files Browse the repository at this point in the history
  • Loading branch information
dreammaster committed Jun 27, 2015
1 parent 7ecf553 commit 7594507
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 134 deletions.
95 changes: 80 additions & 15 deletions engines/sherlock/image_file.cpp
Expand Up @@ -93,9 +93,10 @@ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool
}

// Load data for frame and decompress it
byte *data = new byte[frame._size];
byte *data = new byte[frame._size + 4];
stream.read(data, frame._size);
decompressFrame(frame, data);
Common::fill(data + frame._size, data + frame._size + 4, 0);
frame.decompressFrame(data, _vm->getGameID() == GType_RoseTattoo);
delete[] data;

push_back(frame);
Expand Down Expand Up @@ -134,21 +135,21 @@ void ImageFile::loadPalette(Common::SeekableReadStream &stream) {
}
}

void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
frame._frame.create(frame._width, frame._height, Graphics::PixelFormat::createFormatCLUT8());
byte *dest = (byte *)frame._frame.getPixels();
Common::fill(dest, dest + frame._width * frame._height, 0xff);
void ImageFrame::decompressFrame(const byte *src, bool isRoseTattoo) {
_frame.create(_width, _height, Graphics::PixelFormat::createFormatCLUT8());
byte *dest = (byte *)_frame.getPixels();
Common::fill(dest, dest + _width * _height, 0xff);

if (frame._paletteBase) {
if (_paletteBase) {
// Nibble-packed
for (uint idx = 0; idx < frame._size; ++idx, ++src) {
for (uint idx = 0; idx < _size; ++idx, ++src) {
*dest++ = *src & 0xF;
*dest++ = (*src >> 4);
}
} else if (frame._rleEncoded && _vm->getGameID() == GType_RoseTattoo) {
} else if (_rleEncoded && isRoseTattoo) {
// Rose Tattoo run length encoding doesn't use the RLE marker byte
for (int yp = 0; yp < frame._height; ++yp) {
int xSize = frame._width;
for (int yp = 0; yp < _height; ++yp) {
int xSize = _width;
while (xSize > 0) {
// Skip a given number of pixels
byte skip = *src++;
Expand All @@ -165,11 +166,11 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
}
assert(xSize == 0);
}
} else if (frame._rleEncoded) {
} else if (_rleEncoded) {
// RLE encoded
int frameSize = frame._width * frame._height;
int frameSize = _width * _height;
while (frameSize > 0) {
if (*src == frame._rleMarker) {
if (*src == _rleMarker) {
byte rleColor = src[1];
byte rleCount = src[2];
src += 3;
Expand All @@ -184,7 +185,7 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
assert(frameSize == 0);
} else {
// Uncompressed frame
Common::copy(src, src + frame._width * frame._height, dest);
Common::copy(src, src + _width * _height, dest);
}
}

Expand Down Expand Up @@ -1007,4 +1008,68 @@ void ImageFile3DO::loadFont(Common::SeekableReadStream &stream) {
delete[] widthTablePtr;
}

/*----------------------------------------------------------------*/

StreamingImageFile::StreamingImageFile() {
_frameNumber = 0;
_stream = nullptr;
_flags = 0;
_scaleVal = 0;
_zPlacement = 0;
}

StreamingImageFile::~StreamingImageFile() {
close();
}

void StreamingImageFile::load(Common::SeekableReadStream *stream, bool compressed) {
_stream = stream;
_compressed = compressed;
_frameNumber = -1;
}

void StreamingImageFile::close() {
delete _stream;
_stream = nullptr;
_frameNumber = -1;
}

void StreamingImageFile::getNextFrame() {
// Don't proceed if we're already at the end of the stream
if (_stream->pos() >= _stream->size())
return;

// Increment frame number
++_frameNumber;

// If necessary, decompress the next frame
Common::SeekableReadStream *frameStream = _stream;
if (_compressed) {
uint32 inSize = _stream->readUint32LE();
Resources::decompressLZ(*_stream, _buffer, STREAMING_BUFFER_SIZE, inSize);
frameStream = new Common::MemoryReadStream(_buffer, 11, DisposeAfterUse::NO);
}

// Load the data for the frame
_imageFrame._width = frameStream->readUint16LE() + 1;
_imageFrame._height = frameStream->readUint16LE() + 1;
_imageFrame._paletteBase = frameStream->readByte();
_imageFrame._rleEncoded = frameStream->readByte() == 1;
_imageFrame._offset.x = frameStream->readByte();
_imageFrame._offset.y = frameStream->readByte();
_imageFrame._size = frameStream->readUint16LE() - 11;
_imageFrame._rleMarker = frameStream->readByte();

// Decode the frame
if (_compressed) {
delete frameStream;
_imageFrame.decompressFrame(_buffer + 11, true);
} else {
byte *data = new byte[_imageFrame._size];
_stream->read(data, _imageFrame._size);
_imageFrame.decompressFrame(_buffer + 11, true);
delete[] data;
}
}

} // End of namespace Sherlock
58 changes: 53 additions & 5 deletions engines/sherlock/image_file.h
Expand Up @@ -45,6 +45,11 @@ struct ImageFrame {
byte _rleMarker;
Graphics::Surface _frame;

/**
* Decompress a single frame for the sprite
*/
void decompressFrame(const byte *src, bool isRoseTattoo);

/**
* Return the frame width adjusted by a specified scale amount
*/
Expand Down Expand Up @@ -79,11 +84,6 @@ class ImageFile : public Common::Array<ImageFrame> {
* Gets the palette at the start of the sprite file
*/
void loadPalette(Common::SeekableReadStream &stream);

/**
* Decompress a single frame for the sprite
*/
void decompressFrame(ImageFrame &frame, const byte *src);
public:
byte _palette[256 * 3];
public:
Expand Down Expand Up @@ -154,6 +154,54 @@ class ImageFile3DO : public ImageFile { // Common::Array<ImageFrame> {
static void setVm(SherlockEngine *vm);
};

#define STREAMING_BUFFER_SIZE 65536

class StreamingImageFile {
private:
int _frameNumber;
Common::SeekableReadStream *_stream;
bool _compressed;
byte _buffer[STREAMING_BUFFER_SIZE];
public:
ImageFrame _imageFrame;

Common::Point _position; // Animation position
Common::Rect _oldBounds; // Bounds of previous frame
Common::Rect _removeBounds; // Remove area for just drawn frame

int _flags; // Flags
int _scaleVal; // Specifies the scale amount
int _zPlacement; // Used by doBgAnim for determining Z order
public:
StreamingImageFile();
~StreamingImageFile();

/**
* Initialize reading of the specified stream
*/
void load(Common::SeekableReadStream *stream, bool compressed);

/**
* Close the streamining image file
*/
void close();

/**
* Get the next frame of the file
*/
void getNextFrame();

/**
* Returns whether there are any remaining frames or not
*/
bool active() const { return _stream != nullptr && _stream->pos() < _stream->size(); }

/**
* Return the current frame number
*/
int frameNumber() const { return _frameNumber; }
};

} // End of namespace Sherlock

#endif
36 changes: 0 additions & 36 deletions engines/sherlock/objects.cpp
Expand Up @@ -1498,42 +1498,6 @@ void CAnim::load3DO(Common::SeekableReadStream &s, uint32 dataOffset) {

/*----------------------------------------------------------------*/

CAnimStream::CAnimStream() {
_images = nullptr;
_imageFrame = nullptr;
_frameNumber = 0;
_flags = 0;
_scaleVal = 0;
_zPlacement = 0;
}

CAnimStream::~CAnimStream() {
delete _images;
}

void CAnimStream::load(Common::SeekableReadStream *stream) {
delete _images;
_images = new ImageFile(*stream, false);
_imageFrame = &(*_images)[0];
_frameNumber = 0;
}

void CAnimStream::close() {
delete _images;
_images = nullptr;
_imageFrame = nullptr;
_frameNumber = 0;
}

void CAnimStream::getNextFrame() {
if (++_frameNumber < (int)_images->size())
_imageFrame = &(*_images)[_frameNumber];
else
_imageFrame = nullptr;
}

/*----------------------------------------------------------------*/

SceneImage::SceneImage() {
_images = nullptr;
_maxFrames = 0;
Expand Down
38 changes: 0 additions & 38 deletions engines/sherlock/objects.h
Expand Up @@ -458,44 +458,6 @@ struct CAnim {
void load3DO(Common::SeekableReadStream &s, uint32 dataOffset);
};

class CAnimStream {
ImageFile *_images;
int _frameNumber;
public:
ImageFrame *_imageFrame;

Common::Point _position; // Animation position
Common::Rect _oldBounds; // Bounds of previous frame
Common::Rect _removeBounds; // Remove area for just drawn frame

int _flags; // Flags
int _scaleVal; // Specifies the scale amount
int _zPlacement; // Used by doBgAnim for determining Z order
public:
CAnimStream();
~CAnimStream();

/**
* Load the animation's images
*/
void load(Common::SeekableReadStream *stream);

/**
* Close any currently active animation
*/
void close();

/**
* Get the next frame of the animation
*/
void getNextFrame();

/**
* Returns whether the animation is active
*/
bool active() const { return _imageFrame != nullptr; }
};

struct SceneImage {
ImageFile *_images; // Object images
int _maxFrames; // How many frames in object
Expand Down
2 changes: 1 addition & 1 deletion engines/sherlock/scalpel/scalpel_scene.cpp
Expand Up @@ -574,7 +574,7 @@ int ScalpelScene::startCAnim(int cAnimNum, int playRate) {
//rrmStream->seek(rrmStream->readUint32LE());

// Load the canimation into the cache
Common::SeekableReadStream *imgStream = !_lzwMode ? roomStream->readStream(cAnim._dataSize) :
Common::SeekableReadStream *imgStream = !_compressed ? roomStream->readStream(cAnim._dataSize) :
Resources::decompressLZ(*roomStream, cAnim._dataSize);
res.addToCache(fname, *imgStream);

Expand Down

0 comments on commit 7594507

Please sign in to comment.