aboutsummaryrefslogtreecommitdiff
path: root/engines/sherlock/sprite.cpp
blob: ca709321551d1a90f1a958f5946bae192109410c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/* 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 "sherlock/sprite.h"
#include "sherlock/screen.h"
#include "common/debug.h"

namespace Sherlock {

Sprite::Sprite(Common::SeekableReadStream &stream, bool skipPal) {
	Common::fill(&_palette[0], &_palette[PALETTE_SIZE], 0);
	load(stream, skipPal);
}

Sprite::~Sprite() {
	for (uint idx = 0; idx < size(); ++idx)
		(*this)[idx]._frame.free();
}

/**
 * Load the data of the sprite
 */
void Sprite::load(Common::SeekableReadStream &stream, bool skipPal) {
	loadPalette(stream);

    while (stream.pos() < stream.size()) {
		SpriteFrame frame;
		frame._width = stream.readUint16LE() + 1;
		frame._height = stream.readUint16LE() + 1;
		frame._flags = stream.readByte();
		frame._position.x = stream.readUint16LE();
		frame._position.y = stream.readByte();
        
		frame._rleEncoded = !skipPal && (frame._position.x == 1);

		if (frame._flags & 0xFF) {
			// Nibble packed frame data
			frame._size = (frame._width * frame._height) / 2;
		} else if (frame._rleEncoded) {
            // this size includes the header size, which we subtract
			frame._size = stream.readUint16LE() - 11;
			frame._rleMarker = stream.readByte();
        } else {
			// Uncompressed data
			frame._size = frame._width * frame._height;
        }

		// Load data for frame and decompress it
		byte *data = new byte[frame._size];
		stream.read(data, frame._size);
        decompressFrame(frame, data);		
		delete data;

		push_back(frame);
    }
}

/**
 * Gets the palette at the start of the sprite file
 */
void Sprite::loadPalette(Common::SeekableReadStream &stream) {
	// Read in the palette
	int v1 = stream.readUint16LE() + 1;
	int v2 = stream.readUint16LE() + 1;
	int size = v1 * v2;
	assert((size - 12) == PALETTE_SIZE);

	stream.seek(4 + 12, SEEK_CUR);
	stream.read(&_palette[0], PALETTE_SIZE);
}

/**
 * Decompress a single frame for the sprite
 */
void Sprite::decompressFrame(SpriteFrame &frame, const byte *src) {
	frame._frame.create(frame._width, frame._height, Graphics::PixelFormat::createFormatCLUT8());

	if (frame._flags & 0xFF) {
	    debug("TODO: Sprite::decompressFrame() 4-bits/pixel\n");
	} else if (frame._rleEncoded) {
		// RLE encoded
	    byte *dst = (byte *)frame._frame.getPixels();

		int size = frame._width * frame._height;
		while (size > 0) {
			if (*src == frame._rleMarker) {
			    byte rleColor = src[1];
			    byte rleCount = src[2];
			    src += 3;
			    size -= rleCount;
			    while (rleCount--)
			        *dst++ = rleColor;
			} else {
				*dst++ = *src++;
				--size;
			}
		}
		assert(size == 0);
	} else {
		// Uncompressed frame
		Common::copy(src, src + frame._width * frame._height,
			(byte *)frame._frame.getPixels());
	}
}

} // End of namespace Sherlock