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
24 #include "queen/bankman.h"
25 #include "queen/resource.h"
26
27 #include "common/debug.h"
28
29 namespace Queen {
30
BankManager(Resource * res)31 BankManager::BankManager(Resource *res)
32 : _res(res) {
33 memset(_frames, 0, sizeof(_frames));
34 memset(_banks, 0, sizeof(_banks));
35 }
36
~BankManager()37 BankManager::~BankManager() {
38 for (uint32 i = 0; i < MAX_BANKS_NUMBER; ++i) {
39 close(i);
40 }
41 eraseFrames(true);
42 }
43
load(const char * bankname,uint32 bankslot)44 void BankManager::load(const char *bankname, uint32 bankslot) {
45 debug(9, "BankManager::load(%s, %d)", bankname, bankslot);
46
47 assert(bankslot < MAX_BANKS_NUMBER);
48 PackedBank *bank = &_banks[bankslot];
49
50 if (!scumm_stricmp(bankname, bank->name)) {
51 debug(9, "BankManager::load() bank '%s' already loaded", bankname);
52 return;
53 }
54
55 close(bankslot);
56
57 if (_res->getPlatform() == Common::kPlatformAmiga && !_res->fileExists(bankname)) {
58 debug(9, "BankManager::load() bank '%s' doesn't exist", bankname);
59 return;
60 }
61
62 bank->data = _res->loadFile(bankname);
63
64 if (_res->getPlatform() == Common::kPlatformAmiga) {
65 uint16 entries = READ_BE_UINT16(bank->data + 4);
66 debug(9, "BankManager::load() entries = %d", entries);
67 assert(entries < MAX_BANK_SIZE);
68 uint32 offset = 6;
69 _banks[bankslot].indexes[0] = offset;
70 for (uint16 i = 1; i <= entries; ++i) {
71 _banks[bankslot].indexes[i] = offset;
72 uint16 dataSize = READ_BE_UINT16(bank->data + offset + 10);
73 offset += dataSize + 12;
74 }
75 } else {
76 uint16 entries = READ_LE_UINT16(bank->data);
77 debug(9, "BankManager::load() entries = %d", entries);
78 assert(entries < MAX_BANK_SIZE);
79 uint32 offset = 2;
80 _banks[bankslot].indexes[0] = offset;
81 for (uint16 i = 1; i <= entries; ++i) {
82 _banks[bankslot].indexes[i] = offset;
83 uint16 w = READ_LE_UINT16(bank->data + offset + 0);
84 uint16 h = READ_LE_UINT16(bank->data + offset + 2);
85 offset += w * h + 8;
86 }
87 }
88
89 // mark this bank as loaded
90 strcpy(bank->name, bankname);
91 }
92
convertPlanarBitmap(uint8 * dst,int dstPitch,const uint8 * src,int w,int h,int plane)93 static void convertPlanarBitmap(uint8 *dst, int dstPitch, const uint8 *src, int w, int h, int plane) {
94 assert(w != 0 && h != 0);
95 int planarSize = plane * h * w * 2;
96 uint8 *planarBuf = new uint8[ planarSize ];
97 uint8 *dstPlanar = planarBuf;
98 while (planarSize > 0) {
99 if (src[0] == 0) {
100 int count = src[1];
101 memset(dstPlanar, 0, count);
102 dstPlanar += count;
103 src += 2;
104 planarSize -= count;
105 } else {
106 *dstPlanar++ = *src++;
107 --planarSize;
108 }
109 }
110
111 src = planarBuf;
112 int i = 0;
113 int planeSize = h * w * 2;
114 while (h--) {
115 for (int x = 0; x < w * 2; ++x) {
116 for (int b = 0; b < 8; ++b) {
117 const uint8 mask = (1 << (7 - b));
118 uint8 color = 0;
119 for (int p = 0; p < plane; ++p) {
120 if (src[planeSize * p + i] & mask) {
121 color |= (1 << p);
122 }
123 }
124 dst[8 * x + b] = color;
125 }
126 ++i;
127 }
128 dst += dstPitch;
129 }
130
131 delete[] planarBuf;
132 }
133
unpack(uint32 srcframe,uint32 dstframe,uint32 bankslot)134 void BankManager::unpack(uint32 srcframe, uint32 dstframe, uint32 bankslot) {
135 debug(9, "BankManager::unpack(%d, %d, %d)", srcframe, dstframe, bankslot);
136
137 assert(bankslot < MAX_BANKS_NUMBER);
138 PackedBank *bank = &_banks[bankslot];
139 assert(bank->data != NULL);
140
141 assert(dstframe < MAX_FRAMES_NUMBER);
142 BobFrame *bf = &_frames[dstframe];
143 delete[] bf->data;
144 bf->data = NULL;
145
146 const uint8 *p = bank->data + bank->indexes[srcframe];
147
148 if (_res->getPlatform() == Common::kPlatformAmiga) {
149 uint16 w = READ_BE_UINT16(p + 0);
150 uint16 h = READ_BE_UINT16(p + 2);
151 uint16 plane = READ_BE_UINT16(p + 4);
152 bf->xhotspot = READ_BE_UINT16(p + 6);
153 bf->yhotspot = READ_BE_UINT16(p + 8);
154 bf->width = w * 16;
155 bf->height = h;
156
157 uint32 size = bf->width * bf->height;
158 if (size != 0) {
159 bf->data = new uint8[ size ];
160 convertPlanarBitmap(bf->data, bf->width, p + 12, w, h, plane);
161 }
162 } else {
163 bf->width = READ_LE_UINT16(p + 0);
164 bf->height = READ_LE_UINT16(p + 2);
165 bf->xhotspot = READ_LE_UINT16(p + 4);
166 bf->yhotspot = READ_LE_UINT16(p + 6);
167
168 uint32 size = bf->width * bf->height;
169 if (size != 0) {
170 bf->data = new uint8[ size ];
171 memcpy(bf->data, p + 8, size);
172 }
173 }
174 }
175
overpack(uint32 srcframe,uint32 dstframe,uint32 bankslot)176 void BankManager::overpack(uint32 srcframe, uint32 dstframe, uint32 bankslot) {
177 debug(9, "BankManager::overpack(%d, %d, %d)", srcframe, dstframe, bankslot);
178
179 assert(bankslot < MAX_BANKS_NUMBER);
180 PackedBank *bank = &_banks[bankslot];
181 assert(bank->data != NULL);
182
183 assert(dstframe < MAX_FRAMES_NUMBER);
184 BobFrame *bf = &_frames[dstframe];
185
186 const uint8 *p = bank->data + bank->indexes[srcframe];
187
188 if (_res->getPlatform() == Common::kPlatformAmiga) {
189 uint16 w = READ_BE_UINT16(p + 0);
190 uint16 h = READ_BE_UINT16(p + 2);
191 uint16 plane = READ_BE_UINT16(p + 4);
192 uint16 src_w = w * 16;
193 uint16 src_h = h;
194
195 if (bf->width < src_w || bf->height < src_h) {
196 unpack(srcframe, dstframe, bankslot);
197 } else {
198 convertPlanarBitmap(bf->data, bf->width, p + 12, w, h, plane);
199 }
200 } else {
201 uint16 src_w = READ_LE_UINT16(p + 0);
202 uint16 src_h = READ_LE_UINT16(p + 2);
203
204 // unpack if destination frame is smaller than source
205 if (bf->width < src_w || bf->height < src_h) {
206 unpack(srcframe, dstframe, bankslot);
207 } else {
208 // copy data 'over' destination frame (without updating frame header)
209 memcpy(bf->data, p + 8, src_w * src_h);
210 }
211 }
212 }
213
close(uint32 bankslot)214 void BankManager::close(uint32 bankslot) {
215 debug(9, "BankManager::close(%d)", bankslot);
216 assert(bankslot < MAX_BANKS_NUMBER);
217 PackedBank *bank = &_banks[bankslot];
218 delete[] bank->data;
219 memset(bank, 0, sizeof(PackedBank));
220 }
221
fetchFrame(uint32 index)222 BobFrame *BankManager::fetchFrame(uint32 index) {
223 debug(9, "BankManager::fetchFrame(%d)", index);
224 assert(index < MAX_FRAMES_NUMBER);
225 BobFrame *bf = &_frames[index];
226 assert((bf->width == 0 && bf->height == 0) || bf->data != 0);
227 return bf;
228 }
229
eraseFrame(uint32 index)230 void BankManager::eraseFrame(uint32 index) {
231 debug(9, "BankManager::eraseFrame(%d)", index);
232 assert(index < MAX_FRAMES_NUMBER);
233 BobFrame *bf = &_frames[index];
234 delete[] bf->data;
235 memset(bf, 0, sizeof(BobFrame));
236 }
237
eraseFrames(bool joe)238 void BankManager::eraseFrames(bool joe) {
239 for (uint32 i = joe ? 0 : FRAMES_JOE; i < MAX_FRAMES_NUMBER; ++i) {
240 eraseFrame(i);
241 }
242 }
243
244 } // End of namespace Queen
245