diff options
Diffstat (limited to 'engines/scumm/resource.cpp')
-rw-r--r-- | engines/scumm/resource.cpp | 520 |
1 files changed, 276 insertions, 244 deletions
diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index c872a83d14..0448f60593 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/str.h" @@ -55,7 +52,7 @@ enum { -extern const char *resTypeFromId(int id); +extern const char *nameOfResType(ResType type); static uint16 newTag2Old(uint32 newTag); static const byte *findResourceSmall(uint32 tag, const byte *searchin); @@ -86,8 +83,8 @@ void ScummEngine::openRoom(const int room) { // Load the disk numer / room offs (special case for room 0 exists because // room 0 contains the data which is used to create the roomno / roomoffs // tables -- hence obviously we mustn't use those when loading room 0. - const uint32 diskNumber = room ? _res->roomno[rtRoom][room] : 0; - const uint32 room_offs = room ? _res->roomoffs[rtRoom][room] : 0; + const uint32 diskNumber = room ? _res->_types[rtRoom][room]._roomno : 0; + const uint32 room_offs = room ? _res->_types[rtRoom][room]._roomoffs : 0; // FIXME: Since room_offs is const, clearly the following loop either // is never entered, or loops forever (if it wasn't for the return/error @@ -97,7 +94,7 @@ void ScummEngine::openRoom(const int room) { while (room_offs != RES_INVALID_OFFSET) { if (room_offs != 0 && room != 0 && _game.heversion < 98) { - _fileOffset = _res->roomoffs[rtRoom][room]; + _fileOffset = _res->_types[rtRoom][room]._roomoffs; return; } @@ -125,7 +122,7 @@ void ScummEngine::openRoom(const int room) { return; deleteRoomOffsets(); readRoomsOffsets(); - _fileOffset = _res->roomoffs[rtRoom][room]; + _fileOffset = _res->_types[rtRoom][room]._roomoffs; if (_fileOffset != 8) return; @@ -160,15 +157,13 @@ void ScummEngine::closeRoom() { /** Delete the currently loaded room offsets. */ void ScummEngine::deleteRoomOffsets() { for (int i = 0; i < _numRooms; i++) { - if (_res->roomoffs[rtRoom][i] != RES_INVALID_OFFSET) - _res->roomoffs[rtRoom][i] = 0; + if (_res->_types[rtRoom][i]._roomoffs != RES_INVALID_OFFSET) + _res->_types[rtRoom][i]._roomoffs = 0; } } /** Read room offsets */ void ScummEngine::readRoomsOffsets() { - debug(9, "readRoomOffsets()"); - if (_game.features & GF_SMALL_HEADER) { _fileHandle->seek(12, SEEK_SET); // Directly searching for the room offset block would be more generic... } else { @@ -179,8 +174,8 @@ void ScummEngine::readRoomsOffsets() { while (num--) { int room = _fileHandle->readByte(); int offset = _fileHandle->readUint32LE(); - if (_res->roomoffs[rtRoom][room] != RES_INVALID_OFFSET) { - _res->roomoffs[rtRoom][room] = offset; + if (_res->_types[rtRoom][room]._roomoffs != RES_INVALID_OFFSET) { + _res->_types[rtRoom][room]._roomoffs = offset; } } } @@ -303,6 +298,7 @@ void ScummEngine::readIndexFile() { break; numblock++; + debug(2, "Reading index block of type '%s', size %d", tag2str(blocktype), itemsize); readIndexBlock(blocktype, itemsize); } @@ -352,7 +348,6 @@ void ScummEngine_v7::readIndexBlock(uint32 blocktype, uint32 itemsize) { char *ptr; switch (blocktype) { case MKTAG('A','N','A','M'): // Used by: The Dig, FT - debug(9, "found ANAM block, reading audio names"); num = _fileHandle->readUint16LE(); ptr = (char*)malloc(num * 9); _fileHandle->read(ptr, num * 9); @@ -421,7 +416,6 @@ void ScummEngine::readIndexBlock(uint32 blocktype, uint32 itemsize) { break; case MKTAG('D','O','B','J'): - debug(9, "found DOBJ block, reading object table"); readGlobalObjects(); break; @@ -488,73 +482,78 @@ void ScummEngine::readArrayFromIndexFile() { error("readArrayFromIndexFile() not supported in pre-V6 games"); } -int ScummEngine::readResTypeList(int id) { - int num; - int i; - - debug(9, "readResTypeList(%s)", resTypeFromId(id)); +int ScummEngine::readResTypeList(ResType type) { + uint num; + ResId idx; if (_game.version == 8) num = _fileHandle->readUint32LE(); else num = _fileHandle->readUint16LE(); - if (num != _res->num[id]) { - error("Invalid number of %ss (%d) in directory", resTypeFromId(id), num); + if (num != _res->_types[type].size()) { + error("Invalid number of %ss (%d) in directory", nameOfResType(type), num); } - for (i = 0; i < num; i++) { - _res->roomno[id][i] = _fileHandle->readByte(); + debug(2, " readResTypeList(%s): %d entries", nameOfResType(type), num); + + + for (idx = 0; idx < num; idx++) { + _res->_types[type][idx]._roomno = _fileHandle->readByte(); } - for (i = 0; i < num; i++) { - _res->roomoffs[id][i] = _fileHandle->readUint32LE(); + for (idx = 0; idx < num; idx++) { + _res->_types[type][idx]._roomoffs = _fileHandle->readUint32LE(); } return num; } -int ScummEngine_v70he::readResTypeList(int id) { - int num; - int i; +int ScummEngine_v70he::readResTypeList(ResType type) { + uint num; + ResId idx; - num = ScummEngine::readResTypeList(id); + num = ScummEngine::readResTypeList(type); - if (id == rtRoom) - for (i = 0; i < num; i++) { - _heV7RoomIntOffsets[i] = _res->roomoffs[rtRoom][i]; + if (type == rtRoom) + for (idx = 0; idx < num; idx++) { + _heV7RoomIntOffsets[idx] = _res->_types[rtRoom][idx]._roomoffs; } - for (i = 0; i < num; i++) { - _res->globsize[id][i] = _fileHandle->readUint32LE(); + for (idx = 0; idx < num; idx++) { + // The globsize is currently not being used + /*_res->_types[type][idx]._globsize =*/ _fileHandle->readUint32LE(); } return num; } -void ResourceManager::allocResTypeData(int id, uint32 tag, int num_, const char *name_, int mode_) { - debug(9, "allocResTypeData(%s/%s,%s,%d,%d)", resTypeFromId(id), name_, tag2str(TO_BE_32(tag)), num_, mode_); - assert(id >= 0 && id < (int)(ARRAYSIZE(this->mode))); +void ResourceManager::allocResTypeData(ResType type, uint32 tag, int num, ResTypeMode mode) { + debug(2, "allocResTypeData(%s,%s,%d,%d)", nameOfResType(type), tag2str(TO_BE_32(tag)), num, mode); + assert(type >= 0 && type < (int)(ARRAYSIZE(_types))); - if (num_ >= 8000) - error("Too many %ss (%d) in directory", name_, num_); + if (num >= 8000) + error("Too many %s resources (%d) in directory", nameOfResType(type), num); - mode[id] = mode_; - num[id] = num_; - tags[id] = tag; - name[id] = name_; - address[id] = (byte **)calloc(num_, sizeof(void *)); - flags[id] = (byte *)calloc(num_, sizeof(byte)); - status[id] = (byte *)calloc(num_, sizeof(byte)); + _types[type]._mode = mode; + _types[type]._tag = tag; - if (mode_) { - roomno[id] = (byte *)calloc(num_, sizeof(byte)); - roomoffs[id] = (uint32 *)calloc(num_, sizeof(uint32)); + // If there was data in there, let's clear it out completely. This is important + // in case we are restarting the game. + _types[type].clear(); + _types[type].resize(num); + +/* + TODO: Use multiple Resource subclasses, one for each res mode; then, + given them serializability. + if (mode) { + _types[type].roomno = (byte *)calloc(num, sizeof(byte)); + _types[type].roomoffs = (uint32 *)calloc(num, sizeof(uint32)); } if (_vm->_game.heversion >= 70) { - globsize[id] = (uint32 *)calloc(num_, sizeof(uint32)); + _types[type].globsize = (uint32 *)calloc(num, sizeof(uint32)); } - +*/ } void ScummEngine::loadCharset(int no) { @@ -588,16 +587,14 @@ void ScummEngine::nukeCharset(int i) { _res->nukeResource(rtCharset, i); } -void ScummEngine::ensureResourceLoaded(int type, int i) { - void *addr = NULL; - - debugC(DEBUG_RESOURCE, "ensureResourceLoaded(%s,%d)", resTypeFromId(type), i); +void ScummEngine::ensureResourceLoaded(ResType type, ResId idx) { + debugC(DEBUG_RESOURCE, "ensureResourceLoaded(%s,%d)", nameOfResType(type), idx); - if ((type == rtRoom) && i > 0x7F && _game.version < 7 && _game.heversion <= 71) { - i = _resourceMapper[i & 0x7F]; + if ((type == rtRoom) && idx > 0x7F && _game.version < 7 && _game.heversion <= 71) { + idx = _resourceMapper[idx & 0x7F]; } - // FIXME: This check used to be "i==0". However, that causes + // FIXME: This check used to be "idx==0". However, that causes // problems when using this function to ensure charset 0 is loaded. // This is done for many games, e.g. Zak256 or Indy3 (EGA and VGA). // For now we restrict the check to anything which is not a charset. @@ -608,27 +605,24 @@ void ScummEngine::ensureResourceLoaded(int type, int i) { // our code base? After all we also have to add special cases for many // of our script opcodes that check for the (invalid) actor 0... so // maybe both issues are related... - if (type != rtCharset && i == 0) + if (type != rtCharset && idx == 0) return; - if (i <= _res->num[type]) - addr = _res->address[type][i]; - - if (addr) + if (idx <= _res->_types[type].size() && _res->_types[type][idx]._address) return; - loadResource(type, i); + loadResource(type, idx); - if (_game.version == 5 && type == rtRoom && i == _roomResource) + if (_game.version == 5 && type == rtRoom && (int)idx == _roomResource) VAR(VAR_ROOM_FLAG) = 1; } -int ScummEngine::loadResource(int type, int idx) { +int ScummEngine::loadResource(ResType type, ResId idx) { int roomNr; uint32 fileOffs; uint32 size, tag; - debugC(DEBUG_RESOURCE, "loadResource(%s,%d)", resTypeFromId(type), idx); + debugC(DEBUG_RESOURCE, "loadResource(%s,%d)", nameOfResType(type), idx); if (type == rtCharset && (_game.features & GF_SMALL_HEADER)) { loadCharset(idx); @@ -637,8 +631,8 @@ int ScummEngine::loadResource(int type, int idx) { roomNr = getResourceRoomNr(type, idx); - if (idx >= _res->num[type]) - error("%s %d undefined %d %d", _res->name[type], idx, _res->num[type], roomNr); + if (idx >= _res->_types[type].size()) + error("%s %d undefined %d %d", nameOfResType(type), idx, _res->_types[type].size(), roomNr); if (roomNr == 0) roomNr = _roomResource; @@ -672,11 +666,19 @@ int ScummEngine::loadResource(int type, int idx) { return readSoundResource(idx); } + // Sanity check: Is this the right tag for this resource type? + // + // Currently disabled for newer HE games because they use different + // tags. For example, for rtRoom, 'ROOM' changed to 'RMDA'; and for + // rtImage, 'AWIZ' and 'MULT' can both occur simultaneously. + // On the long run, it would be preferable to not turn this check off, + // but instead to explicitly support the variations in the HE games. tag = _fileHandle->readUint32BE(); - - if (tag != _res->tags[type] && _game.heversion < 70) { - error("%s %d not in room %d at %d+%d in file %s", - _res->name[type], idx, roomNr, + if (tag != _res->_types[type]._tag && _game.heversion < 70) { + error("Unknown res tag '%s' encountered (expected '%s') " + "while trying to load res (%s,%d) in room %d at %d+%d in file %s", + tag2str(tag), tag2str(_res->_types[type]._tag), + nameOfResType(type), idx, roomNr, _fileOffset, fileOffs, _fileHandle->getName()); } @@ -697,35 +699,33 @@ int ScummEngine::loadResource(int type, int idx) { return 1; } -int ScummEngine::getResourceRoomNr(int type, int idx) { +int ScummEngine::getResourceRoomNr(ResType type, ResId idx) { if (type == rtRoom && _game.heversion < 70) return idx; - return _res->roomno[type][idx]; + return _res->_types[type][idx]._roomno; } -uint32 ScummEngine::getResourceRoomOffset(int type, int idx) { +uint32 ScummEngine::getResourceRoomOffset(ResType type, ResId idx) { if (type == rtRoom) { return (_game.version == 8) ? 8 : 0; } - return _res->roomoffs[type][idx]; + return _res->_types[type][idx]._roomoffs; } -uint32 ScummEngine_v70he::getResourceRoomOffset(int type, int idx) { +uint32 ScummEngine_v70he::getResourceRoomOffset(ResType type, ResId idx) { if (type == rtRoom) { return _heV7RoomIntOffsets[idx]; } - return _res->roomoffs[type][idx]; + return _res->_types[type][idx]._roomoffs; } -int ScummEngine::getResourceSize(int type, int idx) { +int ScummEngine::getResourceSize(ResType type, ResId idx) { byte *ptr = getResourceAddress(type, idx); assert(ptr); - MemBlkHeader *hdr = (MemBlkHeader *)(ptr - sizeof(MemBlkHeader)); - - return hdr->size; + return _res->_types[type][idx]._size; } -byte *ScummEngine::getResourceAddress(int type, int idx) { +byte *ScummEngine::getResourceAddress(ResType type, ResId idx) { byte *ptr; if (_game.heversion >= 80 && type == rtString) @@ -734,33 +734,30 @@ byte *ScummEngine::getResourceAddress(int type, int idx) { if (!_res->validateResource("getResourceAddress", type, idx)) return NULL; - if (!_res->address[type]) { - debugC(DEBUG_RESOURCE, "getResourceAddress(%s,%d), _res->address[type] == NULL", resTypeFromId(type), idx); - return NULL; - } - - if (_res->mode[type] && !_res->address[type][idx]) { + // If the resource is missing, but loadable from the game data files, try to do so. + if (!_res->_types[type][idx]._address && _res->_types[type]._mode != kDynamicResTypeMode) { ensureResourceLoaded(type, idx); } - if (!(ptr = (byte *)_res->address[type][idx])) { - debugC(DEBUG_RESOURCE, "getResourceAddress(%s,%d) == NULL", resTypeFromId(type), idx); + ptr = (byte *)_res->_types[type][idx]._address; + if (!ptr) { + debugC(DEBUG_RESOURCE, "getResourceAddress(%s,%d) == NULL", nameOfResType(type), idx); return NULL; } _res->setResourceCounter(type, idx, 1); - debugC(DEBUG_RESOURCE, "getResourceAddress(%s,%d) == %p", resTypeFromId(type), idx, ptr + sizeof(MemBlkHeader)); - return ptr + sizeof(MemBlkHeader); + debugC(DEBUG_RESOURCE, "getResourceAddress(%s,%d) == %p", nameOfResType(type), idx, ptr); + return ptr; } -byte *ScummEngine::getStringAddress(int i) { - byte *addr = getResourceAddress(rtString, i); +byte *ScummEngine::getStringAddress(ResId idx) { + byte *addr = getResourceAddress(rtString, idx); return addr; } -byte *ScummEngine_v6::getStringAddress(int i) { - byte *addr = getResourceAddress(rtString, i); +byte *ScummEngine_v6::getStringAddress(ResId idx) { + byte *addr = getResourceAddress(rtString, idx); if (addr == NULL) return NULL; // Skip over the ArrayHeader @@ -772,35 +769,42 @@ byte *ScummEngine::getStringAddressVar(int i) { } void ResourceManager::increaseExpireCounter() { - if (!(++_expireCounter)) { - increaseResourceCounter(); + ++_expireCounter; + if (_expireCounter == 0) { // overflow? + increaseResourceCounters(); } } -void ResourceManager::increaseResourceCounter() { - int i, j; - byte counter; - - for (i = rtFirst; i <= rtLast; i++) { - for (j = num[i]; --j >= 0;) { - counter = flags[i][j] & RF_USAGE; +void ResourceManager::increaseResourceCounters() { + for (ResType type = rtFirst; type <= rtLast; type = ResType(type + 1)) { + ResId idx = _types[type].size(); + while (idx-- > 0) { + byte counter = _types[type][idx].getResourceCounter(); if (counter && counter < RF_USAGE_MAX) { - setResourceCounter(i, j, counter + 1); + setResourceCounter(type, idx, counter + 1); } } } } -void ResourceManager::setResourceCounter(int type, int idx, byte flag) { - flags[type][idx] &= ~RF_USAGE; - flags[type][idx] |= flag; +void ResourceManager::setResourceCounter(ResType type, ResId idx, byte counter) { + _types[type][idx].setResourceCounter(counter); +} + +void ResourceManager::Resource::setResourceCounter(byte counter) { + _flags &= RF_LOCK; // Clear lower 7 bits, preserve the lock bit. + _flags |= counter; // Update the usage counter +} + +byte ResourceManager::Resource::getResourceCounter() const { + return _flags & RF_USAGE; } /* 2 bytes safety area to make "precaching" of bytes in the gdi drawer easier */ #define SAFETY_AREA 2 -byte *ResourceManager::createResource(int type, int idx, uint32 size) { - debugC(DEBUG_RESOURCE, "_res->createResource(%s,%d,%d)", resTypeFromId(type), idx, size); +byte *ResourceManager::createResource(ResType type, ResId idx, uint32 size) { + debugC(DEBUG_RESOURCE, "_res->createResource(%s,%d,%d)", nameOfResType(type), idx, size); if (!validateResource("allocating", type, idx)) return NULL; @@ -810,31 +814,62 @@ byte *ResourceManager::createResource(int type, int idx, uint32 size) { // cases. For instance, Zak tries to reload the intro music // while it's playing. See bug #1253171. - if (address[type][idx] && (type == rtSound || type == rtScript || type == rtCostume)) - return address[type][idx] + sizeof(MemBlkHeader); + if (_types[type][idx]._address && (type == rtSound || type == rtScript || type == rtCostume)) + return _types[type][idx]._address; } nukeResource(type, idx); expireResources(size); - void *ptr = calloc(size + sizeof(MemBlkHeader) + SAFETY_AREA, 1); + byte *ptr = (byte *)calloc(size + SAFETY_AREA, 1); if (ptr == NULL) { - error("createResource(%s,%d): Out of memory while allocating %d", resTypeFromId(type), idx, size); + error("createResource(%s,%d): Out of memory while allocating %d", nameOfResType(type), idx, size); } _allocatedSize += size; - address[type][idx] = (byte *)ptr; - ((MemBlkHeader *)ptr)->size = size; + _types[type][idx]._address = ptr; + _types[type][idx]._size = size; setResourceCounter(type, idx, 1); - return (byte *)ptr + sizeof(MemBlkHeader); /* skip header */ + return ptr; +} + +ResourceManager::Resource::Resource() { + _address = 0; + _size = 0; + _flags = 0; + _status = 0; + _roomno = 0; + _roomoffs = 0; +} + +ResourceManager::Resource::~Resource() { + delete _address; + _address = 0; } -ResourceManager::ResourceManager(ScummEngine *vm) { - memset(this, 0, sizeof(ResourceManager)); - _vm = vm; -// _allocatedSize = 0; +void ResourceManager::Resource::nuke() { + delete _address; + _address = 0; + _size = 0; + _flags = 0; + _status &= ~RS_MODIFIED; +} + +ResourceManager::ResTypeData::ResTypeData() { + _mode = kDynamicResTypeMode; + _tag = 0; +} + +ResourceManager::ResTypeData::~ResTypeData() { +} + +ResourceManager::ResourceManager(ScummEngine *vm) : _vm(vm) { + _allocatedSize = 0; + _maxHeapThreshold = 0; + _minHeapThreshold = 0; + _expireCounter = 0; } ResourceManager::~ResourceManager() { @@ -848,30 +883,20 @@ void ResourceManager::setHeapThreshold(int min, int max) { _minHeapThreshold = min; } -bool ResourceManager::validateResource(const char *str, int type, int idx) const { - if (type < rtFirst || type > rtLast || (uint) idx >= (uint)num[type]) { - error("%s Illegal Glob type %s (%d) num %d", str, resTypeFromId(type), type, idx); +bool ResourceManager::validateResource(const char *str, ResType type, ResId idx) const { + if (type < rtFirst || type > rtLast || (uint)idx >= (uint)_types[type].size()) { + error("%s Illegal Glob type %s (%d) num %d", str, nameOfResType(type), type, idx); return false; } return true; } -void ResourceManager::nukeResource(int type, int idx) { - byte *ptr; - - if (!address[type]) - return; - - assert(idx >= 0 && idx < num[type]); - - ptr = address[type][idx]; +void ResourceManager::nukeResource(ResType type, ResId idx) { + byte *ptr = _types[type][idx]._address; if (ptr != NULL) { - debugC(DEBUG_RESOURCE, "nukeResource(%s,%d)", resTypeFromId(type), idx); - address[type][idx] = 0; - flags[type][idx] = 0; - status[type][idx] &= ~RS_MODIFIED; - _allocatedSize -= ((MemBlkHeader *)ptr)->size; - free(ptr); + debugC(DEBUG_RESOURCE, "nukeResource(%s,%d)", nameOfResType(type), idx); + _allocatedSize -= _types[type][idx]._size; + _types[type][idx].nuke(); } } @@ -900,77 +925,96 @@ int ScummEngine::getResourceDataSize(const byte *ptr) const { return READ_BE_UINT32(ptr - 4) - _resourceHeaderSize; } -void ResourceManager::lock(int type, int i) { - if (!validateResource("Locking", type, i)) +void ResourceManager::lock(ResType type, ResId idx) { + if (!validateResource("Locking", type, idx)) return; - flags[type][i] |= RF_LOCK; + _types[type][idx].lock(); } -void ResourceManager::unlock(int type, int i) { - if (!validateResource("Unlocking", type, i)) +void ResourceManager::unlock(ResType type, ResId idx) { + if (!validateResource("Unlocking", type, idx)) return; - flags[type][i] &= ~RF_LOCK; + _types[type][idx].unlock(); } -bool ResourceManager::isLocked(int type, int i) const { - if (!validateResource("isLocked", type, i)) +bool ResourceManager::isLocked(ResType type, ResId idx) const { + if (!validateResource("isLocked", type, idx)) return false; - return (flags[type][i] & RF_LOCK) != 0; + return _types[type][idx].isLocked(); +} + +void ResourceManager::Resource::lock() { + _flags |= RF_LOCK; +} + +void ResourceManager::Resource::unlock() { + _flags &= ~RF_LOCK; } -bool ScummEngine::isResourceInUse(int type, int i) const { - if (!_res->validateResource("isResourceInUse", type, i)) +bool ResourceManager::Resource::isLocked() const { + return (_flags & RF_LOCK) != 0; +} + +bool ScummEngine::isResourceInUse(ResType type, ResId idx) const { + if (!_res->validateResource("isResourceInUse", type, idx)) return false; switch (type) { case rtRoom: - return _roomResource == (byte)i; + return _roomResource == (byte)idx; case rtRoomImage: - return _roomResource == (byte)i; + return _roomResource == (byte)idx; case rtRoomScripts: - return _roomResource == (byte)i; + return _roomResource == (byte)idx; case rtScript: - return isScriptInUse(i); + return isScriptInUse(idx); case rtCostume: - return isCostumeInUse(i); + return isCostumeInUse(idx); case rtSound: // Sound resource 1 is used for queued speech - if (_game.heversion >= 60 && i == 1) + if (_game.heversion >= 60 && idx == 1) return true; else - return _sound->isSoundInUse(i); + return _sound->isSoundInUse(idx); case rtCharset: - return _charset->getCurID() == i; + return _charset->getCurID() == (int)idx; case rtImage: - return _res->isModified(type, i) != 0; + return _res->isModified(type, idx) != 0; case rtSpoolBuffer: - return _sound->isSoundRunning(10000 + i) != 0; + return _sound->isSoundRunning(10000 + idx) != 0; default: return false; } } -void ResourceManager::setModified(int type, int i) { - if (!validateResource("Modified", type, i)) +void ResourceManager::setModified(ResType type, ResId idx) { + if (!validateResource("Modified", type, idx)) return; - status[type][i] |= RS_MODIFIED; + _types[type][idx].setModified(); } -bool ResourceManager::isModified(int type, int i) const { - if (!validateResource("isModified", type, i)) +bool ResourceManager::isModified(ResType type, ResId idx) const { + if (!validateResource("isModified", type, idx)) return false; - return (status[type][i] & RS_MODIFIED) != 0; + return _types[type][idx].isModified(); +} + +void ResourceManager::Resource::setModified() { + _status |= RS_MODIFIED; +} + +bool ResourceManager::Resource::isModified() const { + return (_status & RS_MODIFIED) != 0; } void ResourceManager::expireResources(uint32 size) { - int i, j; - byte flag; byte best_counter; - int best_type, best_res = 0; + ResType best_type; + int best_res = 0; uint32 oldAllocatedSize; if (_expireCounter != 0xFF) { _expireCounter = 0xFF; - increaseResourceCounter(); + increaseResourceCounters(); } if (size + _allocatedSize < _maxHeapThreshold) @@ -979,60 +1023,58 @@ void ResourceManager::expireResources(uint32 size) { oldAllocatedSize = _allocatedSize; do { - best_type = 0; + best_type = rtInvalid; best_counter = 2; - for (i = rtFirst; i <= rtLast; i++) - if (mode[i]) { - for (j = num[i]; --j >= 0;) { - flag = flags[i][j]; - if (!(flag & RF_LOCK) && flag >= best_counter && address[i][j] && !_vm->isResourceInUse(i, j)) { - best_counter = flag; - best_type = i; - best_res = j; + for (ResType type = rtFirst; type <= rtLast; type = ResType(type + 1)) { + if (_types[type]._mode != kDynamicResTypeMode) { + // Resources of this type can be reloaded from the data files, + // so we can potentially unload them to free memory. + ResId idx = _types[type].size(); + while (idx-- > 0) { + Resource &tmp = _types[type][idx]; + byte counter = tmp.getResourceCounter(); + if (!tmp.isLocked() && counter >= best_counter && tmp._address && !_vm->isResourceInUse(type, idx)) { + best_counter = counter; + best_type = type; + best_res = idx; } } } + } if (!best_type) break; nukeResource(best_type, best_res); } while (size + _allocatedSize > _minHeapThreshold); - increaseResourceCounter(); + increaseResourceCounters(); debugC(DEBUG_RESOURCE, "Expired resources, mem %d -> %d", oldAllocatedSize, _allocatedSize); } void ResourceManager::freeResources() { - int i, j; - for (i = rtFirst; i <= rtLast; i++) { - for (j = num[i]; --j >= 0;) { - if (isResourceLoaded(i, j)) - nukeResource(i, j); + for (ResType type = rtFirst; type <= rtLast; type = ResType(type + 1)) { + ResId idx = _types[type].size(); + while (idx-- > 0) { + if (isResourceLoaded(type, idx)) + nukeResource(type, idx); } - free(address[i]); - free(flags[i]); - free(status[i]); - free(roomno[i]); - free(roomoffs[i]); - - free(globsize[i]); + _types[type].clear(); } } -void ScummEngine::loadPtrToResource(int type, int resindex, const byte *source) { +void ScummEngine::loadPtrToResource(ResType type, ResId idx, const byte *source) { byte *alloced; int len; - _res->nukeResource(type, resindex); + _res->nukeResource(type, idx); len = resStrLen(source) + 1; - if (len <= 0) return; - alloced = _res->createResource(type, resindex, len); + alloced = _res->createResource(type, idx, len); if (!source) { // Need to refresh the script pointer, since createResource may @@ -1045,32 +1087,30 @@ void ScummEngine::loadPtrToResource(int type, int resindex, const byte *source) } } -bool ResourceManager::isResourceLoaded(int type, int idx) const { +bool ResourceManager::isResourceLoaded(ResType type, ResId idx) const { if (!validateResource("isResourceLoaded", type, idx)) return false; - return address[type][idx] != NULL; + return _types[type][idx]._address != NULL; } void ResourceManager::resourceStats() { - int i, j; uint32 lockedSize = 0, lockedNum = 0; - byte flag; - for (i = rtFirst; i <= rtLast; i++) - for (j = num[i]; --j >= 0;) { - flag = flags[i][j]; - if (flag & RF_LOCK && address[i][j]) { - lockedSize += ((MemBlkHeader *)address[i][j])->size; + for (ResType type = rtFirst; type <= rtLast; type = ResType(type + 1)) { + ResId idx = _types[type].size(); + while (idx-- > 0) { + Resource &tmp = _types[type][idx]; + if (tmp.isLocked() && tmp._address) { + lockedSize += tmp._size; lockedNum++; } } + } debug(1, "Total allocated size=%d, locked=%d(%d)", _allocatedSize, lockedSize, lockedNum); } void ScummEngine_v5::readMAXS(int blockSize) { - debug(9, "ScummEngine_v5 readMAXS: MAXS has blocksize %d", blockSize); - _numVariables = _fileHandle->readUint16LE(); // 800 _fileHandle->readUint16LE(); // 16 _numBitVariables = _fileHandle->readUint16LE(); // 2048 @@ -1099,8 +1139,6 @@ void ScummEngine_v5::readMAXS(int blockSize) { #ifdef ENABLE_SCUMM_7_8 void ScummEngine_v8::readMAXS(int blockSize) { - debug(9, "ScummEngine_v8 readMAXS: MAXS has blocksize %d", blockSize); - _fileHandle->seek(50, SEEK_CUR); // Skip over SCUMM engine version _fileHandle->seek(50, SEEK_CUR); // Skip over data file version _numVariables = _fileHandle->readUint32LE(); // 1500 @@ -1129,8 +1167,6 @@ void ScummEngine_v8::readMAXS(int blockSize) { } void ScummEngine_v7::readMAXS(int blockSize) { - debug(9, "ScummEngine_v7 readMAXS: MAXS has blocksize %d", blockSize); - _fileHandle->seek(50, SEEK_CUR); // Skip over SCUMM engine version _fileHandle->seek(50, SEEK_CUR); // Skip over data file version _numVariables = _fileHandle->readUint16LE(); @@ -1164,8 +1200,6 @@ void ScummEngine_v7::readMAXS(int blockSize) { void ScummEngine_v6::readMAXS(int blockSize) { if (blockSize == 38) { - debug(0, "ScummEngine_v6 readMAXS: MAXS has blocksize %d", blockSize); - _numVariables = _fileHandle->readUint16LE(); _fileHandle->readUint16LE(); _numBitVariables = _fileHandle->readUint16LE(); @@ -1288,35 +1322,35 @@ void ScummEngine::allocateArrays() { } _res->allocResTypeData(rtCostume, (_game.features & GF_NEW_COSTUMES) ? MKTAG('A','K','O','S') : MKTAG('C','O','S','T'), - _numCostumes, "costume", 1); - _res->allocResTypeData(rtRoom, MKTAG('R','O','O','M'), _numRooms, "room", 1); - _res->allocResTypeData(rtRoomImage, MKTAG('R','M','I','M'), _numRooms, "room image", 1); - _res->allocResTypeData(rtRoomScripts, MKTAG('R','M','S','C'), _numRooms, "room script", 1); - _res->allocResTypeData(rtSound, MKTAG('S','O','U','N'), _numSounds, "sound", 2); - _res->allocResTypeData(rtScript, MKTAG('S','C','R','P'), _numScripts, "script", 1); - _res->allocResTypeData(rtCharset, MKTAG('C','H','A','R'), _numCharsets, "charset", 1); - _res->allocResTypeData(rtObjectName, 0, _numNewNames, "new name", 0); - _res->allocResTypeData(rtInventory, 0, _numInventory, "inventory", 0); - _res->allocResTypeData(rtTemp, 0, 10, "temp", 0); - _res->allocResTypeData(rtScaleTable, 0, 5, "scale table", 0); - _res->allocResTypeData(rtActorName, 0, _numActors, "actor name", 0); - _res->allocResTypeData(rtVerb, 0, _numVerbs, "verb", 0); - _res->allocResTypeData(rtString, 0, _numArray, "array", 0); - _res->allocResTypeData(rtFlObject, 0, _numFlObject, "flobject", 0); - _res->allocResTypeData(rtMatrix, 0, 10, "boxes", 0); - _res->allocResTypeData(rtImage, MKTAG('A','W','I','Z'), _numImages, "images", 1); - _res->allocResTypeData(rtTalkie, MKTAG('T','L','K','E'), _numTalkies, "talkie", 1); + _numCostumes, kStaticResTypeMode); + _res->allocResTypeData(rtRoom, MKTAG('R','O','O','M'), _numRooms, kStaticResTypeMode); + _res->allocResTypeData(rtRoomImage, MKTAG('R','M','I','M'), _numRooms, kStaticResTypeMode); + _res->allocResTypeData(rtRoomScripts, MKTAG('R','M','S','C'), _numRooms, kStaticResTypeMode); + _res->allocResTypeData(rtSound, MKTAG('S','O','U','N'), _numSounds, kSoundResTypeMode); + _res->allocResTypeData(rtScript, MKTAG('S','C','R','P'), _numScripts, kStaticResTypeMode); + _res->allocResTypeData(rtCharset, MKTAG('C','H','A','R'), _numCharsets, kStaticResTypeMode); + _res->allocResTypeData(rtObjectName, 0, _numNewNames, kDynamicResTypeMode); + _res->allocResTypeData(rtInventory, 0, _numInventory, kDynamicResTypeMode); + _res->allocResTypeData(rtTemp, 0, 10, kDynamicResTypeMode); + _res->allocResTypeData(rtScaleTable, 0, 5, kDynamicResTypeMode); + _res->allocResTypeData(rtActorName, 0, _numActors, kDynamicResTypeMode); + _res->allocResTypeData(rtVerb, 0, _numVerbs, kDynamicResTypeMode); + _res->allocResTypeData(rtString, 0, _numArray, kDynamicResTypeMode); + _res->allocResTypeData(rtFlObject, 0, _numFlObject, kDynamicResTypeMode); + _res->allocResTypeData(rtMatrix, 0, 10, kDynamicResTypeMode); + _res->allocResTypeData(rtImage, MKTAG('A','W','I','Z'), _numImages, kStaticResTypeMode); + _res->allocResTypeData(rtTalkie, MKTAG('T','L','K','E'), _numTalkies, kStaticResTypeMode); } void ScummEngine_v70he::allocateArrays() { ScummEngine::allocateArrays(); - _res->allocResTypeData(rtSpoolBuffer, 0, 9, "spool buffer", 1); + _res->allocResTypeData(rtSpoolBuffer, 0, 9, kStaticResTypeMode); _heV7RoomIntOffsets = (uint32 *)calloc(_numRooms, sizeof(uint32)); } -void ScummEngine::dumpResource(const char *tag, int idx, const byte *ptr, int length) { +void ScummEngine::dumpResource(const char *tag, int id, const byte *ptr, int length) { char buf[256]; Common::DumpFile out; @@ -1330,7 +1364,7 @@ void ScummEngine::dumpResource(const char *tag, int idx, const byte *ptr, int le else size = READ_BE_UINT32(ptr + 4); - sprintf(buf, "dumps/%s%d.dmp", tag, idx); + sprintf(buf, "dumps/%s%d.dmp", tag, id); out.open(buf); if (out.isOpen() == false) @@ -1499,10 +1533,10 @@ uint16 newTag2Old(uint32 newTag) { } } -const char *resTypeFromId(int id) { +const char *nameOfResType(ResType type) { static char buf[100]; - switch (id) { + switch (type) { case rtRoom: return "Room"; case rtScript: @@ -1545,10 +1579,8 @@ const char *resTypeFromId(int id) { return "Talkie"; case rtSpoolBuffer: return "SpoolBuffer"; - case rtNumTypes: - return "NumTypes"; default: - sprintf(buf, "%d", id); + sprintf(buf, "rt%d", type); return buf; } } |