diff options
author | Eugene Sandulenko | 2005-01-31 03:53:35 +0000 |
---|---|---|
committer | Eugene Sandulenko | 2005-01-31 03:53:35 +0000 |
commit | c32e93672363c2b38b1a636498ce7930864d25e1 (patch) | |
tree | 4b5017bd075e332e4f02a252e6173338a89d7b9d | |
parent | 0c827c0fcf43a764f0e9176d23ccf4567282934a (diff) | |
download | scummvm-rg350-c32e93672363c2b38b1a636498ce7930864d25e1.tar.gz scummvm-rg350-c32e93672363c2b38b1a636498ce7930864d25e1.tar.bz2 scummvm-rg350-c32e93672363c2b38b1a636498ce7930864d25e1.zip |
Support for Mac cursors.
TODO:
o Allow reading from non-processed game executable. Now you need to get
.bin file out of it
o Use color versions of cursors
o Combine MacResExtractor with Win32ResExtractor. Now I just stupidly
create 2 objects and do not use new cursor caching code.
svn-id: r16713
-rw-r--r-- | scumm/cursor.cpp | 7 | ||||
-rw-r--r-- | scumm/intern.h | 2 | ||||
-rw-r--r-- | scumm/resource_v7he.cpp | 258 | ||||
-rw-r--r-- | scumm/resource_v7he.h | 51 | ||||
-rw-r--r-- | scumm/scumm.cpp | 14 |
5 files changed, 323 insertions, 9 deletions
diff --git a/scumm/cursor.cpp b/scumm/cursor.cpp index 4a96da63b7..bfb5ddc6c2 100644 --- a/scumm/cursor.cpp +++ b/scumm/cursor.cpp @@ -144,11 +144,10 @@ void ScummEngine::setCursorFromBuffer(byte *ptr, int width, int height, int pitc } void ScummEngine_v70he::setCursorFromImg(uint img, uint room, uint imgindex) { - // HACK Macintosh cursors aren't supported yet. if (_features & GF_MACINTOSH && _heversion == 72) - return; - - _win32ResExtractor->setCursor(img); + _macResExtractor->setCursor(img); + else + _win32ResExtractor->setCursor(img); } void ScummEngine_v6::setCursorFromImg(uint img, uint room, uint imgindex) { diff --git a/scumm/intern.h b/scumm/intern.h index 97e6441ce8..95590992aa 100644 --- a/scumm/intern.h +++ b/scumm/intern.h @@ -633,6 +633,7 @@ protected: class ScummEngine_v70he : public ScummEngine_v60he { friend class Win32ResExtractor; + friend class MacResExtractor; protected: typedef void (ScummEngine_v70he::*OpcodeProcv70he)(); @@ -644,6 +645,7 @@ protected: const OpcodeEntryv70he *_opcodesv70he; Win32ResExtractor *_win32ResExtractor; + MacResExtractor *_macResExtractor; int _heSndSoundFreq, _heSndOffset, _heSndChannel, _heSndSoundId, _heSndFlags; diff --git a/scumm/resource_v7he.cpp b/scumm/resource_v7he.cpp index b7de79be76..02b02ff844 100644 --- a/scumm/resource_v7he.cpp +++ b/scumm/resource_v7he.cpp @@ -51,7 +51,7 @@ const char *res_types[] = { Win32ResExtractor::Win32ResExtractor(ScummEngine_v70he *scumm) { _vm = scumm; - snprintf(_fileName, 256, "%s.he3", _vm->getGameName()); + _fileName[0] = 0; memset(_cursorCache, 0, sizeof(_cursorCache)); } @@ -146,6 +146,9 @@ int Win32ResExtractor::extractResource(const char *resType, char *resName, byte fi.memory = NULL; fi.file = new File; + if (!_fileName[0]) // We are running for the first time + snprintf(_fileName, 256, "%s.he3", _vm->getGameName()); + /* get file size */ fi.file->open(_fileName); if (!fi.file->isOpen()) { @@ -1257,4 +1260,257 @@ void Win32ResExtractor::fix_win32_image_data_directory(Win32ImageDataDirectory * } +MacResExtractor::MacResExtractor(ScummEngine_v70he *scumm) { + _vm = scumm; + + _fileName[0] = 0; + _resOffset = -1; +} + +void MacResExtractor::setCursor(int id) { + byte *cursorRes = 0, *cursor = 0; + int cursorsize; + int w = 0, h = 0, hotspot_x = 0, hotspot_y = 0; + int keycolor; + + if (!_fileName[0]) // We are running for the first time + if (_vm->_heMacFileNameIndex > 0) { + char buf1[128]; + + snprintf(buf1, 128, "%s.he3", _vm->getGameName()); + _vm->generateMacFileName(buf1, _fileName, 128, 0, _vm->_heMacFileNameIndex); + } + + cursorsize = extractResource(id, &cursorRes); + convertIcons(cursorRes, cursorsize, &cursor, &w, &h, &hotspot_x, &hotspot_y, &keycolor); + + _vm->setCursorHotspot(hotspot_x, hotspot_y); + _vm->setCursorFromBuffer(cursor, w, h, w); + free(cursorRes); + free(cursor); +} + +int MacResExtractor::extractResource(int id, byte **buf) { + File in; + int size; + + in.open(_fileName); + if (!in.isOpen()) { + error("Cannot open file %s", _fileName); + } + + // we haven't calculated it + if (_resOffset == -1) { + if (!init(in)) + error("Invalid file format (%s)", _fileName); + debug(0, "ResOffset: %d", _resOffset); + } + + *buf = getResource(in, "crsr", 1000 + id, &size); + + if (*buf == NULL) + error("Cannot read cursor ID: %d", id); + + return size; +} + +#define MBI_INFOHDR 128 +#define MBI_ZERO1 0 +#define MBI_NAMELEN 1 +#define MBI_ZERO2 74 +#define MBI_ZERO3 82 +#define MBI_DFLEN 83 +#define MBI_RFLEN 87 +#define MAXNAMELEN 63 + +bool MacResExtractor::init(File in) { + byte infoHeader[MBI_INFOHDR]; + int32 data_size, rsrc_size; + int32 data_size_pad, rsrc_size_pad; + int filelen; + + filelen = in.size(); + in.read(infoHeader, MBI_INFOHDR); + + // Following should be 0 bytes + if(infoHeader[MBI_ZERO1] != 0) return false; + + if(infoHeader[MBI_ZERO2] != 0) return false; + + if(infoHeader[MBI_ZERO3] != 0) return false; + + // Filename has a length range + if(infoHeader[MBI_NAMELEN] > MAXNAMELEN) return false; + + // Pull out fork lengths + data_size = READ_BE_UINT32(infoHeader + MBI_DFLEN); + rsrc_size = READ_BE_UINT32(infoHeader + MBI_RFLEN); + + data_size_pad = (((data_size + 127) >> 7) << 7); + rsrc_size_pad = (((rsrc_size + 127) >> 7) << 7); + + // Length check + int sumlen = MBI_INFOHDR + data_size_pad + rsrc_size_pad; + if(sumlen != filelen) return false; + + _resOffset = MBI_INFOHDR + data_size_pad; + + in.seek(_resOffset); + + _dataOffset = in.readUint32BE() + _resOffset; + _mapOffset = in.readUint32BE() + _resOffset; + _dataLength = in.readUint32BE(); + _mapLength = in.readUint32BE(); + + debug(0, "got header: data %d [%d] map %d [%d]", + _dataOffset, _dataLength, _mapOffset, _mapLength); + + readMap(in); + + return true; +} + +byte *MacResExtractor::getResource(File in, const char *typeID, int16 resID, int *size) { + int i; + int typeNum = -1; + int resNum = -1; + byte *buf; + int len; + + for (i = 0; i < _resMap.numTypes; i++) + if (strcmp(_resTypes[i].id, typeID) == 0) { + typeNum = i; + break; + } + + if (typeNum == -1) + return NULL; + + for (i = 0; i < _resTypes[typeNum].items; i++) + if (_resLists[typeNum][i].id == resID) { + resNum = i; + break; + } + + if (resNum == -1) + return NULL; + + in.seek(_dataOffset + _resLists[typeNum][resNum].dataOffset); + + len = in.readUint32BE(); + buf = (byte *)malloc(len); + + in.read(buf, len); + + *size = len; + + return buf; +} + +void MacResExtractor::readMap(File in) { + int i, j, len; + + in.seek(_mapOffset + 22); + + _resMap.resAttr = in.readUint16BE(); + _resMap.typeOffset = in.readUint16BE(); + _resMap.nameOffset = in.readUint16BE(); + _resMap.numTypes = in.readUint16BE(); + _resMap.numTypes++; + + debug(0, "Read %d types, type offset %d, name offset %d", _resMap.numTypes, + _resMap.typeOffset, _resMap.nameOffset); + + in.seek(_mapOffset + _resMap.typeOffset + 2); + _resTypes = new ResType[_resMap.numTypes]; + + for (i = 0; i < _resMap.numTypes; i++) { + in.read(_resTypes[i].id, 4); + _resTypes[i].items = in.readUint16BE(); + _resTypes[i].offset = in.readUint16BE(); + _resTypes[i].items++; + } + + for (i = 0; i < _resMap.numTypes; i++) { + debug(0, "resource '%c%c%c%c': items %d, offset %d", + _resTypes[i].id[0], _resTypes[i].id[1], + _resTypes[i].id[2], _resTypes[i].id[3], + _resTypes[i].items, _resTypes[i].offset); + } + + _resLists = new ResPtr[_resMap.numTypes]; + + for (i = 0; i < _resMap.numTypes; i++) { + _resLists[i] = new Resource[_resTypes[i].items]; + in.seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset); + + for (j = 0; j < _resTypes[i].items; j++) { + ResPtr resPtr = _resLists[i] + j; + + resPtr->id = in.readUint16BE(); + resPtr->nameOffset = in.readUint16BE(); + resPtr->dataOffset = in.readUint32BE(); + in.readUint32BE(); + resPtr->name = 0; + + resPtr->attr = resPtr->dataOffset >> 24; + resPtr->dataOffset &= 0xFFFFFF; + + debug(0, "resource '%c%c%c%c' %d: name %d, data %d, attr %d", + _resTypes[i].id[0], _resTypes[i].id[1], + _resTypes[i].id[2], _resTypes[i].id[3], + resPtr->id, resPtr->nameOffset, resPtr->dataOffset, resPtr->attr); + } + + for (j = 0; j < _resTypes[i].items; j++) { + if (_resLists[i][j].nameOffset != -1) { + in.seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset); + + len = in.readByte(); + _resLists[i][j].name = new byte[len + 1]; + _resLists[i][j].name[len] = 0; + in.read(_resLists[i][j].name, len); + debug(0, "name of %d: %s", _resLists[i][j].id, _resLists[i][j].name); + } + } + } +} + +void MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor) { + Common::MemoryReadStream dis(data, datasize); + int i, b; + byte imageByte; + int ignored; + + ignored = dis.readUint16BE(); // type + ignored = dis.readUint32BE(); // offset to pixle map + ignored = dis.readUint32BE(); // offset to pixel data + ignored = dis.readUint32BE(); // expanded cursor data + ignored = dis.readUint16BE(); // expanded data depth + ignored = dis.readUint32BE(); // reserved + + // Grab icon data + *cursor = (byte *)malloc(256); + for (i = 0; i < 32; i++) { + imageByte = dis.readByte(); + for (b = 0; b < 8; b++) + cursor[0][i*8+b] = (byte)((imageByte & + (0x80 >> b)) > 0? 0x0F: 0x00); + } + + // Grab mask data + for (i = 0; i < 32; i++) { + imageByte = dis.readByte(); + for (b = 0; b < 8; b++) + if ((imageByte & (0x80 >> b)) == 0) + cursor[0][i*8+b] = 0xff; + } + + // Could use DataInputStream - but just 2 bytes + *hotspot_y = dis.readUint16BE(); + *hotspot_x = dis.readUint16BE(); + *w = *h = 16; +} + } // End of namespace Scumm diff --git a/scumm/resource_v7he.h b/scumm/resource_v7he.h index 3aef799933..8144cdd35b 100644 --- a/scumm/resource_v7he.h +++ b/scumm/resource_v7he.h @@ -481,6 +481,57 @@ class Win32ResExtractor { void fix_win32_image_data_directory(Win32ImageDataDirectory *obj); }; +class MacResExtractor { + +public: + MacResExtractor(ScummEngine_v70he *scumm); + ~MacResExtractor() { } + void setCursor(int id) ; + +private: + int extractResource(int id, byte **buf); + bool init(File in); + void readMap(File in); + byte *getResource(File in, const char *typeID, int16 resID, int *size); + void convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor); + + struct ResMap { + int16 resAttr; + int16 typeOffset; + int16 nameOffset; + int16 numTypes; + }; + + struct ResType { + char id[5]; + int16 items; + int16 offset; + }; + + struct Resource { + int16 id; + int16 nameOffset; + byte attr; + int32 dataOffset; + byte *name; + }; + + typedef Resource *ResPtr; + +private: + ScummEngine_v70he *_vm; + char _fileName[256]; + int _resOffset; + int32 _dataOffset; + int32 _dataLength; + int32 _mapOffset; + int32 _mapLength; + ResMap _resMap; + ResType *_resTypes; + ResPtr *_resLists; +}; + } // End of namespace Scumm #endif diff --git a/scumm/scumm.cpp b/scumm/scumm.cpp index d0020de413..5faedb5e5d 100644 --- a/scumm/scumm.cpp +++ b/scumm/scumm.cpp @@ -1046,6 +1046,7 @@ ScummEngine_v6::ScummEngine_v6(GameDetector *detector, OSystem *syst, const Scum ScummEngine_v70he::ScummEngine_v70he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16]) : ScummEngine_v60he(detector, syst, gs, md5sum) { _win32ResExtractor = new Win32ResExtractor(this); + _macResExtractor = new MacResExtractor(this); _heSndSoundId = 0; _heSndOffset = 0; @@ -2763,10 +2764,15 @@ static int generateMacFileName_(const char *filename, char *buf, int bufsize, in for (int i = cont; i < ARRAYSIZE(heMacFileNameTable); i++) { if (!scumm_strnicmp(filename, heMacFileNameTable[i].winName, len)) { - if (heMacFileNameTable[i].hasParens) - snprintf(buf, bufsize, "%s (%c)", heMacFileNameTable[i].macName, num); - else - snprintf(buf, bufsize, "%s %c", heMacFileNameTable[i].macName, num); + if (num == '3') { // special case for cursors + // For mac they're stored in game binary + strncpy(buf, heMacFileNameTable[i].macName, bufsize); + } else { + if (heMacFileNameTable[i].hasParens) + snprintf(buf, bufsize, "%s (%c)", heMacFileNameTable[i].macName, num); + else + snprintf(buf, bufsize, "%s %c", heMacFileNameTable[i].macName, num); + } return i; } |