1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/memstream.h"
24 #include "common/system.h"
25 #include "common/substream.h"
26 #include "common/tokenizer.h"
27
28 #include "graphics/surface.h"
29
30 #include "image/bmp.h"
31
32 #include "petka/flc.h"
33 #include "petka/q_manager.h"
34 #include "petka/petka.h"
35
36 namespace Petka {
37
QManager(PetkaEngine & vm)38 QManager::QManager(PetkaEngine &vm)
39 : _vm(vm) {}
40
init()41 bool QManager::init() {
42 clear();
43
44 Common::ScopedPtr<Common::SeekableReadStream> stream(_vm.openFile("resource.qrc", true));
45 if (!stream) {
46 return false;
47 }
48
49 while (!stream->eos()) {
50 Common::StringTokenizer tokenizer(stream->readLine());
51 if (tokenizer.empty()) {
52 continue;
53 }
54
55 const uint32 id = (uint32)atoi(tokenizer.nextToken().c_str());
56 _isAlwaysNeededMap.setVal(id, tokenizer.nextToken() == "==");
57 _nameMap.setVal(id, tokenizer.nextToken());
58
59 }
60 return true;
61 }
62
findResourceName(uint32 id) const63 Common::String QManager::findResourceName(uint32 id) const {
64 return _nameMap.contains(id) ? _nameMap.getVal(id) : "";
65 }
66
findSoundName(uint32 id) const67 Common::String QManager::findSoundName(uint32 id) const {
68 Common::String name = findResourceName(id);
69 name.toUppercase();
70 if (name.empty() || name.hasSuffix(".WAV")) {
71 return name;
72 }
73 name.erase(name.size() - 3, 3);
74 return name += "WAV";
75 }
76
removeResource(uint32 id)77 void QManager::removeResource(uint32 id) {
78 if (_resourceMap.contains(id)) {
79 _resourceMap.erase(id);
80 }
81 }
82
clearUnneeded()83 void QManager::clearUnneeded() {
84 for (auto it = _resourceMap.begin(); it != _resourceMap.end(); ++it) {
85 if (!_isAlwaysNeededMap.getVal(it->_key)) {
86 _resourceMap.erase(it);
87 }
88 }
89 }
90
getSurface(uint32 id,uint16 w,uint16 h)91 Graphics::Surface *QManager::getSurface(uint32 id, uint16 w, uint16 h) {
92 if (_resourceMap.contains(id)) {
93 const QResource &res = _resourceMap.getVal(id);
94 return res.type == QResource::kSurface ? res.surface : nullptr;
95 }
96
97 QResource &res = _resourceMap.getOrCreateVal(id);
98 res.type = QResource::kSurface;
99 res.surface = new Graphics::Surface;
100 res.surface->create(w, h, _vm._system->getScreenFormat());
101
102 return res.surface;
103 }
104
loadFileStream(uint32 id) const105 Common::SeekableReadStream *QManager::loadFileStream(uint32 id) const {
106 const Common::String &name = findResourceName(id);
107 return name.empty() ? nullptr : _vm.openFile(name, false);
108 }
109
getSurface(uint32 id)110 Graphics::Surface *QManager::getSurface(uint32 id) {
111 if (_resourceMap.contains(id)) {
112 const QResource &res = _resourceMap.getVal(id);
113 return res.type == QResource::kSurface ? res.surface : nullptr;
114 }
115
116 Common::ScopedPtr<Common::SeekableReadStream> stream(loadFileStream(id));
117 if (!stream) {
118 return nullptr;
119 }
120
121 Graphics::Surface *s = loadBitmapSurface(*stream);
122 if (s) {
123 QResource &res = _resourceMap.getOrCreateVal(id);
124 res.type = QResource::kSurface;
125 res.surface = s;
126 return res.surface;
127 }
128
129 return nullptr;
130 }
131
getFlic(uint32 id)132 FlicDecoder *QManager::getFlic(uint32 id) {
133 if (_resourceMap.contains(id)) {
134 const QResource &res = _resourceMap.getVal(id);
135 return res.type == QResource::kFlic ? res.flcDecoder : nullptr;
136 }
137
138 Common::String name = findResourceName(id);
139 Common::SeekableReadStream *stream = _vm.openFile(name, false);
140 if (!stream) {
141 return nullptr;
142 }
143
144 name.erase(name.size() - 3, 3);
145 name.toUppercase();
146 name += "MSK";
147
148 FlicDecoder *flc = new FlicDecoder;
149 flc->load(stream, _vm.openFile(name, false));
150
151 QResource &res = _resourceMap.getOrCreateVal(id);
152 res.type = QResource::kFlic;
153 res.flcDecoder = flc;
154
155 return res.flcDecoder;
156 }
157
clear()158 void QManager::clear() {
159 _resourceMap.clear();
160 _nameMap.clear();
161 _isAlwaysNeededMap.clear();
162 }
163
loadBitmapSurface(Common::SeekableReadStream & stream)164 Graphics::Surface *QManager::loadBitmapSurface(Common::SeekableReadStream &stream) {
165 const uint32 kHeaderSize = 14 + 40;
166 const uint32 kAdditionalDataSize = 8;
167
168 if (stream.readByte() != 'B')
169 return nullptr;
170
171 if (stream.readByte() != 'M')
172 return nullptr;
173
174 uint32 realFileSize = stream.readUint32LE();
175
176 stream.skip(12);
177
178 uint32 width = stream.readUint32LE();
179 uint32 height = stream.readUint32LE();
180
181 stream.skip(2);
182
183 uint16 bitsPerPixel = stream.readUint16LE();
184 if (bitsPerPixel != 16 && bitsPerPixel != 1) {
185 stream.seek(0, SEEK_SET);
186 Image::BitmapDecoder decoder;
187 if (!decoder.loadStream(stream))
188 return nullptr;
189 return decoder.getSurface()->convertTo(g_system->getScreenFormat(), decoder.getPalette());
190 }
191 else if (bitsPerPixel == 1) {
192 Graphics::Surface *s = new Graphics::Surface;
193 s->create(width, height, Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0));
194 return s;
195 }
196
197 stream.seek(0, SEEK_SET);
198 byte *convertedBmp = new byte[realFileSize];
199
200 stream.read(convertedBmp, kHeaderSize);
201 WRITE_LE_INT16(convertedBmp + 28, 24); // bitsPerPixel
202
203 uint32 align = stream.readUint32LE();
204 uint32 fileSize = stream.readUint32LE();
205
206 byte *pixels = convertedBmp + kHeaderSize;
207 uint32 pixelsCount = (fileSize - (kHeaderSize + kAdditionalDataSize) - align + 1) / 2;
208
209 Graphics::PixelFormat fmt(2, 5, 6, 5, 0, 0, 5, 11, 0);
210 while (pixelsCount) {
211 fmt.colorToRGB(stream.readUint16BE(), *(pixels + 2), *(pixels + 1), *pixels);
212 pixels += 3;
213 pixelsCount--;
214 }
215
216 Common::MemoryReadStream convBmpStream(convertedBmp, realFileSize, DisposeAfterUse::YES);
217 Image::BitmapDecoder decoder;
218 if (!decoder.loadStream(convBmpStream))
219 return nullptr;
220
221 return decoder.getSurface()->convertTo(g_system->getScreenFormat(), decoder.getPalette());
222 }
223
~QResource()224 QManager::QResource::~QResource() {
225 if (type == QResource::kSurface && surface) {
226 surface->free();
227 delete surface;
228 } else {
229 delete flcDecoder;
230 }
231 }
232
233 } // End of namespace Petka
234