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/algorithm.h"
24 #include "common/memstream.h"
25 #include "neverhood/resource.h"
26 #include "neverhood/resourceman.h"
27
28 namespace Neverhood {
29
30 // SpriteResource
31
SpriteResource(NeverhoodEngine * vm)32 SpriteResource::SpriteResource(NeverhoodEngine *vm)
33 : _vm(vm), _pixels(NULL) {
34 }
35
~SpriteResource()36 SpriteResource::~SpriteResource() {
37 unload();
38 }
39
draw(Graphics::Surface * destSurface,bool flipX,bool flipY)40 void SpriteResource::draw(Graphics::Surface *destSurface, bool flipX, bool flipY) {
41 if (_pixels) {
42 byte *dest = (byte*)destSurface->getPixels();
43 const int destPitch = destSurface->pitch;
44 if (_rle)
45 unpackSpriteRle(_pixels, _dimensions.width, _dimensions.height, dest, destPitch, flipX, flipY);
46 else
47 unpackSpriteNormal(_pixels, _dimensions.width, _dimensions.height, dest, destPitch, flipX, flipY);
48 }
49 }
50
load(uint32 fileHash,bool doLoadPosition)51 bool SpriteResource::load(uint32 fileHash, bool doLoadPosition) {
52 debug(2, "SpriteResource::load(%08X)", fileHash);
53 unload();
54 _vm->_res->queryResource(fileHash, _resourceHandle);
55 if (_resourceHandle.isValid() && _resourceHandle.type() == kResTypeBitmap) {
56 _vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
57 const byte *spriteData = _resourceHandle.data();
58 NPoint *position = doLoadPosition ? &_position : NULL;
59 parseBitmapResource(spriteData, &_rle, &_dimensions, position, NULL, &_pixels);
60 }
61 return _pixels != NULL;
62 }
63
unload()64 void SpriteResource::unload() {
65 _vm->_res->unloadResource(_resourceHandle);
66 _pixels = NULL;
67 _rle = false;
68 }
69
70 // PaletteResource
71
PaletteResource(NeverhoodEngine * vm)72 PaletteResource::PaletteResource(NeverhoodEngine *vm)
73 : _vm(vm), _palette(NULL) {
74 }
75
~PaletteResource()76 PaletteResource::~PaletteResource() {
77 unload();
78 }
79
load(uint32 fileHash)80 bool PaletteResource::load(uint32 fileHash) {
81 debug(2, "PaletteResource::load(%08X)", fileHash);
82 unload();
83 _vm->_res->queryResource(fileHash, _resourceHandle);
84 if (_resourceHandle.isValid() &&
85 (_resourceHandle.type() == kResTypeBitmap || _resourceHandle.type() == kResTypePalette)) {
86 _vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
87 _palette = _resourceHandle.data();
88 // Check if the palette is stored in a bitmap
89 if (_resourceHandle.type() == kResTypeBitmap)
90 parseBitmapResource(_palette, NULL, NULL, NULL, &_palette, NULL);
91
92 }
93 return _palette != NULL;
94 }
95
unload()96 void PaletteResource::unload() {
97 _vm->_res->unloadResource(_resourceHandle);
98 _palette = NULL;
99 }
100
copyPalette(byte * destPalette)101 void PaletteResource::copyPalette(byte *destPalette) {
102 if (_palette)
103 memcpy(destPalette, _palette, 1024);
104 }
105
106 // AnimResource
107
AnimResource(NeverhoodEngine * vm)108 AnimResource::AnimResource(NeverhoodEngine *vm)
109 : _vm(vm), _width(0), _height(0), _currSpriteData(NULL), _fileHash(0), _paletteData(NULL),
110 _spriteData(NULL), _replEnabled(false), _replOldColor(0), _replNewColor(0) {
111 }
112
~AnimResource()113 AnimResource::~AnimResource() {
114 unload();
115 }
116
draw(uint frameIndex,Graphics::Surface * destSurface,bool flipX,bool flipY)117 void AnimResource::draw(uint frameIndex, Graphics::Surface *destSurface, bool flipX, bool flipY) {
118 const AnimFrameInfo frameInfo = _frames[frameIndex];
119 byte *dest = (byte*)destSurface->getPixels();
120 const int destPitch = destSurface->pitch;
121 _currSpriteData = _spriteData + frameInfo.spriteDataOffs;
122 _width = frameInfo.drawOffset.width;
123 _height = frameInfo.drawOffset.height;
124 if (_replEnabled && _replOldColor != _replNewColor)
125 unpackSpriteRle(_currSpriteData, _width, _height, dest, destPitch, flipX, flipY, _replOldColor, _replNewColor);
126 else
127 unpackSpriteRle(_currSpriteData, _width, _height, dest, destPitch, flipX, flipY);
128 }
129
load(uint32 fileHash)130 bool AnimResource::load(uint32 fileHash) {
131 debug(2, "AnimResource::load(%08X)", fileHash);
132
133 if (fileHash == _fileHash)
134 return true;
135
136 unload();
137
138 _vm->_res->queryResource(fileHash, _resourceHandle);
139 if (!_resourceHandle.isValid() || _resourceHandle.type() != kResTypeAnimation)
140 return false;
141
142 const byte *resourceData, *animList, *frameList;
143 uint16 animInfoStartOfs, animListIndex, animListCount;
144 uint16 frameListStartOfs, frameCount;
145 uint32 spriteDataOfs, paletteDataOfs;
146
147 _vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
148 resourceData = _resourceHandle.data();
149
150 animListCount = READ_LE_UINT16(resourceData);
151 animInfoStartOfs = READ_LE_UINT16(resourceData + 2);
152 spriteDataOfs = READ_LE_UINT32(resourceData + 4);
153 paletteDataOfs = READ_LE_UINT32(resourceData + 8);
154
155 animList = resourceData + 12;
156 for (animListIndex = 0; animListIndex < animListCount; animListIndex++) {
157 debug(8, "hash: %08X", READ_LE_UINT32(animList));
158 if (READ_LE_UINT32(animList) == fileHash)
159 break;
160 animList += 8;
161 }
162
163 if (animListIndex >= animListCount) {
164 _vm->_res->unloadResource(_resourceHandle);
165 return false;
166 }
167
168 _spriteData = resourceData + spriteDataOfs;
169 if (paletteDataOfs > 0)
170 _paletteData = resourceData + paletteDataOfs;
171
172 frameCount = READ_LE_UINT16(animList + 4);
173 frameListStartOfs = READ_LE_UINT16(animList + 6);
174
175 debug(8, "frameCount = %d; frameListStartOfs = %04X; animInfoStartOfs = %04X", frameCount, frameListStartOfs, animInfoStartOfs);
176
177 frameList = resourceData + animInfoStartOfs + frameListStartOfs;
178
179 _frames.clear();
180 _frames.reserve(frameCount);
181
182 for (uint16 frameIndex = 0; frameIndex < frameCount; frameIndex++) {
183 AnimFrameInfo frameInfo;
184 frameInfo.frameHash = READ_LE_UINT32(frameList);
185 frameInfo.counter = READ_LE_UINT16(frameList + 4);
186 frameInfo.drawOffset.x = READ_LE_UINT16(frameList + 6);
187 frameInfo.drawOffset.y = READ_LE_UINT16(frameList + 8);
188 frameInfo.drawOffset.width = READ_LE_UINT16(frameList + 10);
189 frameInfo.drawOffset.height = READ_LE_UINT16(frameList + 12);
190 frameInfo.deltaX = READ_LE_UINT16(frameList + 14);
191 frameInfo.deltaY = READ_LE_UINT16(frameList + 16);
192 frameInfo.collisionBoundsOffset.x = READ_LE_UINT16(frameList + 18);
193 frameInfo.collisionBoundsOffset.y = READ_LE_UINT16(frameList + 20);
194 frameInfo.collisionBoundsOffset.width = READ_LE_UINT16(frameList + 22);
195 frameInfo.collisionBoundsOffset.height = READ_LE_UINT16(frameList + 24);
196 frameInfo.spriteDataOffs = READ_LE_UINT32(frameList + 28);
197 debug(8, "frameHash = %08X; counter = %d; rect = (%d,%d,%d,%d); deltaX = %d; deltaY = %d; collisionBoundsOffset = (%d,%d,%d,%d); spriteDataOffs = %08X",
198 frameInfo.frameHash, frameInfo.counter,
199 frameInfo.drawOffset.x, frameInfo.drawOffset.y, frameInfo.drawOffset.width, frameInfo.drawOffset.height,
200 frameInfo.deltaX, frameInfo.deltaY,
201 frameInfo.collisionBoundsOffset.x, frameInfo.collisionBoundsOffset.y, frameInfo.collisionBoundsOffset.width, frameInfo.collisionBoundsOffset.height,
202 frameInfo.spriteDataOffs);
203 frameList += 32;
204 _frames.push_back(frameInfo);
205 }
206
207 _fileHash = fileHash;
208
209 return true;
210
211 }
212
unload()213 void AnimResource::unload() {
214 _vm->_res->unloadResource(_resourceHandle);
215 _currSpriteData = NULL;
216 _fileHash = 0;
217 _paletteData = NULL;
218 _spriteData = NULL;
219 _replEnabled = true;
220 _replOldColor = 0;
221 _replNewColor = 0;
222 }
223
getFrameIndex(uint32 frameHash)224 int16 AnimResource::getFrameIndex(uint32 frameHash) {
225 int16 frameIndex = -1;
226 for (uint i = 0; i < _frames.size(); i++)
227 if (_frames[i].frameHash == frameHash) {
228 frameIndex = (int16)i;
229 break;
230 }
231 debug(2, "AnimResource::getFrameIndex(%08X) -> %d", frameHash, frameIndex);
232 return frameIndex;
233 }
234
setRepl(byte oldColor,byte newColor)235 void AnimResource::setRepl(byte oldColor, byte newColor) {
236 _replOldColor = oldColor;
237 _replNewColor = newColor;
238 }
239
loadSpriteDimensions(uint32 fileHash)240 NDimensions AnimResource::loadSpriteDimensions(uint32 fileHash) {
241 ResourceHandle resourceHandle;
242 NDimensions dimensions;
243 _vm->_res->queryResource(fileHash, resourceHandle);
244 const byte *resDimensions = resourceHandle.extData();
245 if (resDimensions) {
246 dimensions.width = READ_LE_UINT16(resDimensions + 0);
247 dimensions.height = READ_LE_UINT16(resDimensions + 2);
248 } else {
249 dimensions.width = 0;
250 dimensions.height = 0;
251 }
252 return dimensions;
253 }
254
255 // MouseCursorResource
256
MouseCursorResource(NeverhoodEngine * vm)257 MouseCursorResource::MouseCursorResource(NeverhoodEngine *vm)
258 : _cursorSprite(vm), _cursorNum(4), _currFileHash(0) {
259
260 _rect.width = 32;
261 _rect.height = 32;
262 }
263
load(uint32 fileHash)264 void MouseCursorResource::load(uint32 fileHash) {
265 if (_currFileHash != fileHash) {
266 if (_cursorSprite.load(fileHash) && !_cursorSprite.isRle() &&
267 _cursorSprite.getDimensions().width == 96 && _cursorSprite.getDimensions().height == 224) {
268 _currFileHash = fileHash;
269 } else {
270 unload();
271 }
272 }
273 }
274
unload()275 void MouseCursorResource::unload() {
276 _cursorSprite.unload();
277 _currFileHash = 0;
278 _cursorNum = 4;
279 }
280
getRect()281 NDrawRect& MouseCursorResource::getRect() {
282 static const NPoint kCursorHotSpots[] = {
283 {-15, -5},
284 {-17, -25},
285 {-17, -30},
286 {-14, -1},
287 {-3, -7},
288 {-30, -18},
289 {-1, -18}
290 };
291 _rect.x = kCursorHotSpots[_cursorNum].x;
292 _rect.y = kCursorHotSpots[_cursorNum].y;
293 return _rect;
294 }
295
draw(int frameNum,Graphics::Surface * destSurface)296 void MouseCursorResource::draw(int frameNum, Graphics::Surface *destSurface) {
297 if (_cursorSprite.getPixels()) {
298 const int sourcePitch = (_cursorSprite.getDimensions().width + 3) & 0xFFFC; // 4 byte alignment
299 const int destPitch = destSurface->pitch;
300 const byte *source = _cursorSprite.getPixels() + _cursorNum * (sourcePitch * 32) + frameNum * 32;
301 byte *dest = (byte*)destSurface->getPixels();
302 for (int16 yc = 0; yc < 32; yc++) {
303 memcpy(dest, source, 32);
304 source += sourcePitch;
305 dest += destPitch;
306 }
307 }
308 }
309
310 // TextResource
311
TextResource(NeverhoodEngine * vm)312 TextResource::TextResource(NeverhoodEngine *vm)
313 : _vm(vm), _textData(NULL), _count(0) {
314
315 }
316
~TextResource()317 TextResource::~TextResource() {
318 unload();
319 }
320
load(uint32 fileHash)321 void TextResource::load(uint32 fileHash) {
322 debug(2, "TextResource::load(%08X)", fileHash);
323 unload();
324 _vm->_res->queryResource(fileHash, _resourceHandle);
325 if (_resourceHandle.isValid() && _resourceHandle.type() == kResTypeText) {
326 _vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
327 _textData = _resourceHandle.data();
328 _count = READ_LE_UINT32(_textData);
329 }
330 }
331
unload()332 void TextResource::unload() {
333 _vm->_res->unloadResource(_resourceHandle);
334 _textData = NULL;
335 _count = 0;
336 }
337
getString(uint index,const char * & textEnd)338 const char *TextResource::getString(uint index, const char *&textEnd) {
339 const char *textStart = (const char*)(_textData + 4 + _count * 4 + READ_LE_UINT32(_textData + (index + 1) * 4));
340 textEnd = (const char*)(_textData + 4 + _count * 4 + READ_LE_UINT32(_textData + (index + 2) * 4));
341 return textStart;
342 }
343
344 // DataResource
345
DataResource(NeverhoodEngine * vm)346 DataResource::DataResource(NeverhoodEngine *vm)
347 : _vm(vm) {
348 }
349
~DataResource()350 DataResource::~DataResource() {
351 unload();
352 }
353
load(uint32 fileHash)354 void DataResource::load(uint32 fileHash) {
355 if (_resourceHandle.fileHash() == fileHash)
356 return;
357 const byte *data = NULL;
358 uint32 dataSize = 0;
359 unload();
360 _vm->_res->queryResource(fileHash, _resourceHandle);
361 if (_resourceHandle.isValid() && _resourceHandle.type() == kResTypeData) {
362 _vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
363 data = _resourceHandle.data();
364 dataSize = _resourceHandle.size();
365 }
366 if (data && dataSize) {
367 Common::MemoryReadStream dataS(data, dataSize);
368 uint itemCount = dataS.readUint16LE();
369 uint32 itemStartOffs = 2 + itemCount * 8;
370 debug(2, "itemCount = %d", itemCount);
371 for (uint i = 0; i < itemCount; i++) {
372 dataS.seek(2 + i * 8);
373 DRDirectoryItem drDirectoryItem;
374 drDirectoryItem.nameHash = dataS.readUint32LE();
375 drDirectoryItem.offset = dataS.readUint16LE();
376 drDirectoryItem.type = dataS.readUint16LE();
377 debug(2, "%03d nameHash = %08X; offset = %04X; type = %d", i, drDirectoryItem.nameHash, drDirectoryItem.offset, drDirectoryItem.type);
378 dataS.seek(itemStartOffs + drDirectoryItem.offset);
379 switch (drDirectoryItem.type) {
380 case 1:
381 {
382 debug(3, "NPoint");
383 NPoint point;
384 point.x = dataS.readUint16LE();
385 point.y = dataS.readUint16LE();
386 debug(3, "(%d, %d)", point.x, point.y);
387 drDirectoryItem.offset = _points.size();
388 _points.push_back(point);
389 break;
390 }
391 case 2:
392 {
393 uint count = dataS.readUint16LE();
394 NPointArray *pointArray = new NPointArray();
395 debug(3, "NPointArray; count = %d", count);
396 for (uint j = 0; j < count; j++) {
397 NPoint point;
398 point.x = dataS.readUint16LE();
399 point.y = dataS.readUint16LE();
400 debug(3, "(%d, %d)", point.x, point.y);
401 pointArray->push_back(point);
402 }
403 drDirectoryItem.offset = _pointArrays.size();
404 _pointArrays.push_back(pointArray);
405 break;
406 }
407 case 3:
408 {
409 uint count = dataS.readUint16LE();
410 HitRectList *hitRectList = new HitRectList();
411 debug(3, "HitRectList; count = %d", count);
412 for (uint j = 0; j < count; j++) {
413 HitRect hitRect;
414 hitRect.rect.x1 = dataS.readUint16LE();
415 hitRect.rect.y1 = dataS.readUint16LE();
416 hitRect.rect.x2 = dataS.readUint16LE();
417 hitRect.rect.y2 = dataS.readUint16LE();
418 hitRect.type = dataS.readUint16LE() + 0x5001;
419 debug(3, "(%d, %d, %d, %d) -> %04d", hitRect.rect.x1, hitRect.rect.y1, hitRect.rect.x2, hitRect.rect.y2, hitRect.type);
420 hitRectList->push_back(hitRect);
421 }
422 drDirectoryItem.offset = _hitRectLists.size();
423 _hitRectLists.push_back(hitRectList);
424 break;
425 }
426 case 4:
427 {
428 uint count = dataS.readUint16LE();
429 MessageList *messageList = new MessageList();
430 debug(3, "MessageList; count = %d", count);
431 for (uint j = 0; j < count; j++) {
432 MessageItem messageItem;
433 messageItem.messageNum = dataS.readUint32LE();
434 messageItem.messageValue = dataS.readUint32LE();
435 debug(3, "(%08X, %08X)", messageItem.messageNum, messageItem.messageValue);
436 messageList->push_back(messageItem);
437 }
438 drDirectoryItem.offset = _messageLists.size();
439 _messageLists.push_back(messageList);
440 break;
441 }
442 case 5:
443 {
444 uint count = dataS.readUint16LE();
445 DRSubRectList *drSubRectList = new DRSubRectList();
446 debug(3, "SubRectList; count = %d", count);
447 for (uint j = 0; j < count; j++) {
448 DRSubRect drSubRect;
449 drSubRect.rect.x1 = dataS.readUint16LE();
450 drSubRect.rect.y1 = dataS.readUint16LE();
451 drSubRect.rect.x2 = dataS.readUint16LE();
452 drSubRect.rect.y2 = dataS.readUint16LE();
453 drSubRect.messageListHash = dataS.readUint32LE();
454 drSubRect.messageListItemIndex = dataS.readUint16LE();
455 debug(3, "(%d, %d, %d, %d) -> %08X (%d)", drSubRect.rect.x1, drSubRect.rect.y1, drSubRect.rect.x2, drSubRect.rect.y2, drSubRect.messageListHash, drSubRect.messageListItemIndex);
456 drSubRectList->push_back(drSubRect);
457 }
458 drDirectoryItem.offset = _drSubRectLists.size();
459 _drSubRectLists.push_back(drSubRectList);
460 break;
461 }
462 case 6:
463 {
464 DRRect drRect;
465 drRect.rect.x1 = dataS.readUint16LE();
466 drRect.rect.y1 = dataS.readUint16LE();
467 drRect.rect.x2 = dataS.readUint16LE();
468 drRect.rect.y2 = dataS.readUint16LE();
469 drRect.subRectIndex = dataS.readUint16LE();
470 debug(3, "(%d, %d, %d, %d) -> %d", drRect.rect.x1, drRect.rect.y1, drRect.rect.x2, drRect.rect.y2, drRect.subRectIndex);
471 drDirectoryItem.offset = _drRects.size();
472 _drRects.push_back(drRect);
473 break;
474 }
475 case 7:
476 {
477 uint count = dataS.readUint16LE();
478 NRectArray *rectArray = new NRectArray();
479 debug(3, "NRectArray; count = %d", count);
480 for (uint j = 0; j < count; j++) {
481 NRect rect;
482 rect.x1 = dataS.readUint16LE();
483 rect.y1 = dataS.readUint16LE();
484 rect.x2 = dataS.readUint16LE();
485 rect.y2 = dataS.readUint16LE();
486 debug(3, "(%d, %d, %d, %d)", rect.x1, rect.y1, rect.x2, rect.y2);
487 rectArray->push_back(rect);
488 }
489 drDirectoryItem.offset = _rectArrays.size();
490 _rectArrays.push_back(rectArray);
491 break;
492 }
493 default:
494 break;
495 }
496 _directory.push_back(drDirectoryItem);
497 }
498 }
499 }
500
unload()501 void DataResource::unload() {
502 _directory.clear();
503 _points.clear();
504 for (Common::Array<NPointArray*>::iterator it = _pointArrays.begin(); it != _pointArrays.end(); ++it)
505 delete (*it);
506 _pointArrays.clear();
507 for (Common::Array<NRectArray*>::iterator it = _rectArrays.begin(); it != _rectArrays.end(); ++it)
508 delete (*it);
509 _rectArrays.clear();
510 for (Common::Array<HitRectList*>::iterator it = _hitRectLists.begin(); it != _hitRectLists.end(); ++it)
511 delete (*it);
512 _hitRectLists.clear();
513 for (Common::Array<MessageList*>::iterator it = _messageLists.begin(); it != _messageLists.end(); ++it)
514 delete (*it);
515 _messageLists.clear();
516 _drRects.clear();
517 for (Common::Array<DRSubRectList*>::iterator it = _drSubRectLists.begin(); it != _drSubRectLists.end(); ++it)
518 delete (*it);
519 _drSubRectLists.clear();
520 _vm->_res->unloadResource(_resourceHandle);
521 }
522
getPoint(uint32 nameHash)523 NPoint DataResource::getPoint(uint32 nameHash) {
524 DataResource::DRDirectoryItem *drDirectoryItem = findDRDirectoryItem(nameHash, 1);
525 return drDirectoryItem ? _points[drDirectoryItem->offset] : NPoint();
526 }
527
getPointArray(uint32 nameHash)528 NPointArray *DataResource::getPointArray(uint32 nameHash) {
529 DataResource::DRDirectoryItem *drDirectoryItem = findDRDirectoryItem(nameHash, 2);
530 return drDirectoryItem ? _pointArrays[drDirectoryItem->offset] : NULL;
531 }
532
getRectArray(uint32 nameHash)533 NRectArray *DataResource::getRectArray(uint32 nameHash) {
534 DataResource::DRDirectoryItem *drDirectoryItem = findDRDirectoryItem(nameHash, 3);
535 return drDirectoryItem ? _rectArrays[drDirectoryItem->offset] : NULL;
536 }
537
getHitRectList()538 HitRectList *DataResource::getHitRectList() {
539 DataResource::DRDirectoryItem *drDirectoryItem = findDRDirectoryItem(calcHash("HitArray"), 3);
540 return drDirectoryItem ? _hitRectLists[drDirectoryItem->offset] : NULL;
541 }
542
getMessageListAtPos(int16 klaymenX,int16 klaymenY,int16 mouseX,int16 mouseY)543 MessageList *DataResource::getMessageListAtPos(int16 klaymenX, int16 klaymenY, int16 mouseX, int16 mouseY) {
544 for (uint i = 0; i < _drRects.size(); i++) {
545 if (klaymenX >= _drRects[i].rect.x1 && klaymenX <= _drRects[i].rect.x2 &&
546 klaymenY >= _drRects[i].rect.y1 && klaymenY <= _drRects[i].rect.y2) {
547 DRSubRectList *drSubRectList = _drSubRectLists[_drRects[i].subRectIndex];
548 for (uint j = 0; j < drSubRectList->size(); j++) {
549 DRSubRect &subRect = (*drSubRectList)[j];
550 if (mouseX >= subRect.rect.x1 && mouseX <= subRect.rect.x2 &&
551 mouseY >= subRect.rect.y1 && mouseY <= subRect.rect.y2) {
552 return _messageLists[subRect.messageListItemIndex];
553 }
554 }
555 }
556 }
557 return NULL;
558 }
559
findDRDirectoryItem(uint32 nameHash,uint16 type)560 DataResource::DRDirectoryItem *DataResource::findDRDirectoryItem(uint32 nameHash, uint16 type) {
561 for (Common::Array<DRDirectoryItem>::iterator it = _directory.begin(); it != _directory.end(); it++)
562 if ((*it).nameHash == nameHash && (*it).type == type)
563 return &(*it);
564 return NULL;
565 }
566
calcHash(const char * value)567 uint32 calcHash(const char *value) {
568 uint32 hash = 0, shiftValue = 0;
569 while (*value != 0) {
570 char ch = *value++;
571 if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
572 if (ch >= 'a' && ch <= 'z')
573 ch -= 32;
574 else if (ch >= '0' && ch <= '9')
575 ch += 22;
576 shiftValue += ch - 64;
577 if (shiftValue >= 32)
578 shiftValue -= 32;
579 hash ^= 1 << shiftValue;
580 }
581 }
582 return hash;
583 }
584
585 } // End of namespace Neverhood
586