mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-23 02:44:56 +00:00
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
This commit is contained in:
parent
0c827c0fcf
commit
c32e936723
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user