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
|