mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-21 11:41:25 +00:00
SCI: Add support for SCI2.1 chunk resources
And if no scripts are present, but chunk 0 is present, load resources from there. This fixes the Lighthouse SCI2.1 demo. svn-id: r51696
This commit is contained in:
parent
5962b0bbe2
commit
44f12117f2
@ -182,7 +182,7 @@ ResourceType ResourceManager::convertResType(byte type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//-- Resource main functions --
|
//-- Resource main functions --
|
||||||
Resource::Resource(ResourceId id) : _id(id) {
|
Resource::Resource(ResourceManager *resMan, ResourceId id) : _resMan(resMan), _id(id) {
|
||||||
data = NULL;
|
data = NULL;
|
||||||
size = 0;
|
size = 0;
|
||||||
_fileOffset = 0;
|
_fileOffset = 0;
|
||||||
@ -705,6 +705,86 @@ void IntMapResourceSource::scanSource(ResourceManager *resMan) {
|
|||||||
resMan->readAudioMapSCI11(this);
|
resMan->readAudioMapSCI11(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
|
||||||
|
// Chunk resources are resources that hold other resources. They are normally called
|
||||||
|
// when using the kLoadChunk SCI2.1 kernel function. However, for example, the Lighthouse
|
||||||
|
// SCI2.1 demo has a chunk but no scripts outside of the chunk.
|
||||||
|
|
||||||
|
// A chunk resource is pretty straightforward in terms of layout
|
||||||
|
// It begins with 11-byte entries in the header:
|
||||||
|
// =========
|
||||||
|
// b resType
|
||||||
|
// w nEntry
|
||||||
|
// dw offset
|
||||||
|
// dw length
|
||||||
|
|
||||||
|
ChunkResourceSource::ChunkResourceSource(const Common::String &name, uint16 number)
|
||||||
|
: ResourceSource(kSourceChunk, name) {
|
||||||
|
|
||||||
|
_number = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChunkResourceSource::scanSource(ResourceManager *resMan) {
|
||||||
|
Resource *chunk = resMan->findResource(ResourceId(kResourceTypeChunk, _number), false);
|
||||||
|
|
||||||
|
if (!chunk)
|
||||||
|
error("Trying to load non-existent chunk");
|
||||||
|
|
||||||
|
byte *ptr = chunk->data;
|
||||||
|
uint32 firstOffset = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
ResourceType type = resMan->convertResType(*ptr);
|
||||||
|
uint16 number = READ_LE_UINT16(ptr + 1);
|
||||||
|
ResourceId id(type, number);
|
||||||
|
|
||||||
|
ResourceEntry entry;
|
||||||
|
entry.offset = READ_LE_UINT32(ptr + 3);
|
||||||
|
entry.length = READ_LE_UINT32(ptr + 7);
|
||||||
|
|
||||||
|
_resMap[id] = entry;
|
||||||
|
ptr += 11;
|
||||||
|
|
||||||
|
debugC(kDebugLevelResMan, 2, "Found %s in chunk %d", id.toString().c_str(), _number);
|
||||||
|
|
||||||
|
resMan->updateResource(id, this, entry.length);
|
||||||
|
|
||||||
|
// There's no end marker to the data table, but the first resource
|
||||||
|
// begins directly after the entry table. So, when we hit the first
|
||||||
|
// resource, we're at the end of the entry table.
|
||||||
|
|
||||||
|
if (!firstOffset)
|
||||||
|
firstOffset = entry.offset;
|
||||||
|
|
||||||
|
if ((ptr - chunk->data) >= firstOffset)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChunkResourceSource::loadResource(ResourceManager *resMan, Resource *res) {
|
||||||
|
Resource *chunk = resMan->findResource(ResourceId(kResourceTypeChunk, _number), false);
|
||||||
|
|
||||||
|
if (!_resMap.contains(res->_id))
|
||||||
|
error("Trying to load non-existent resource from chunk %d: %s %d", _number, getResourceTypeName(res->_id.getType()), res->_id.getNumber());
|
||||||
|
|
||||||
|
ResourceEntry entry = _resMap[res->_id];
|
||||||
|
res->data = new byte[entry.length];
|
||||||
|
res->size = entry.length;
|
||||||
|
res->_header = 0;
|
||||||
|
res->_headerSize = 0;
|
||||||
|
res->_status = kResStatusAllocated;
|
||||||
|
|
||||||
|
// Copy the resource data over
|
||||||
|
memcpy(res->data, chunk->data + entry.offset, entry.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::addResourcesFromChunk(uint16 id) {
|
||||||
|
addSource(new ChunkResourceSource(Common::String::printf("Chunk %d", id), id));
|
||||||
|
scanNewSources();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void ResourceManager::freeResourceSources() {
|
void ResourceManager::freeResourceSources() {
|
||||||
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it)
|
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it)
|
||||||
@ -770,6 +850,21 @@ void ResourceManager::init() {
|
|||||||
default:
|
default:
|
||||||
error("resMan: Couldn't determine view type");
|
error("resMan: Couldn't determine view type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
if (getSciVersion() >= SCI_VERSION_2_1) {
|
||||||
|
// If we have no scripts, but chunk 0 is present, open up the chunk
|
||||||
|
// to try to get to any scripts in there. The Lighthouse SCI2.1 demo
|
||||||
|
// does exactly this.
|
||||||
|
|
||||||
|
Common::List<ResourceId> *scriptList = listResources(kResourceTypeScript);
|
||||||
|
|
||||||
|
if (scriptList->empty() && testResource(ResourceId(kResourceTypeChunk, 0)))
|
||||||
|
addResourcesFromChunk(0);
|
||||||
|
|
||||||
|
delete scriptList;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceManager::~ResourceManager() {
|
ResourceManager::~ResourceManager() {
|
||||||
@ -1544,7 +1639,7 @@ void MacResourceForkResourceSource::scanSource(ResourceManager *resMan) {
|
|||||||
void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size) {
|
void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size) {
|
||||||
// Adding new resource only if it does not exist
|
// Adding new resource only if it does not exist
|
||||||
if (_resMap.contains(resId) == false) {
|
if (_resMap.contains(resId) == false) {
|
||||||
Resource *res = new Resource(resId);
|
Resource *res = new Resource(this, resId);
|
||||||
_resMap.setVal(resId, res);
|
_resMap.setVal(resId, res);
|
||||||
res->_source = src;
|
res->_source = src;
|
||||||
res->_fileOffset = offset;
|
res->_fileOffset = offset;
|
||||||
@ -1559,7 +1654,7 @@ Resource *ResourceManager::updateResource(ResourceId resId, ResourceSource *src,
|
|||||||
if (_resMap.contains(resId)) {
|
if (_resMap.contains(resId)) {
|
||||||
res = _resMap.getVal(resId);
|
res = _resMap.getVal(resId);
|
||||||
} else {
|
} else {
|
||||||
res = new Resource(resId);
|
res = new Resource(this, resId);
|
||||||
_resMap.setVal(resId, res);
|
_resMap.setVal(resId, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1585,21 +1680,21 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream
|
|||||||
case kResVersionSci0Sci1Early:
|
case kResVersionSci0Sci1Early:
|
||||||
case kResVersionSci1Middle:
|
case kResVersionSci1Middle:
|
||||||
w = file->readUint16LE();
|
w = file->readUint16LE();
|
||||||
type = (ResourceType)(w >> 11);
|
type = _resMan->convertResType(w >> 11);
|
||||||
number = w & 0x7FF;
|
number = w & 0x7FF;
|
||||||
szPacked = file->readUint16LE() - 4;
|
szPacked = file->readUint16LE() - 4;
|
||||||
szUnpacked = file->readUint16LE();
|
szUnpacked = file->readUint16LE();
|
||||||
wCompression = file->readUint16LE();
|
wCompression = file->readUint16LE();
|
||||||
break;
|
break;
|
||||||
case kResVersionSci1Late:
|
case kResVersionSci1Late:
|
||||||
type = (ResourceType)(file->readByte() & 0x7F);
|
type = _resMan->convertResType(file->readByte());
|
||||||
number = file->readUint16LE();
|
number = file->readUint16LE();
|
||||||
szPacked = file->readUint16LE() - 4;
|
szPacked = file->readUint16LE() - 4;
|
||||||
szUnpacked = file->readUint16LE();
|
szUnpacked = file->readUint16LE();
|
||||||
wCompression = file->readUint16LE();
|
wCompression = file->readUint16LE();
|
||||||
break;
|
break;
|
||||||
case kResVersionSci11:
|
case kResVersionSci11:
|
||||||
type = (ResourceType)(file->readByte() & 0x7F);
|
type = _resMan->convertResType(file->readByte());
|
||||||
number = file->readUint16LE();
|
number = file->readUint16LE();
|
||||||
szPacked = file->readUint16LE();
|
szPacked = file->readUint16LE();
|
||||||
szUnpacked = file->readUint16LE();
|
szUnpacked = file->readUint16LE();
|
||||||
@ -1616,7 +1711,7 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream
|
|||||||
break;
|
break;
|
||||||
#ifdef ENABLE_SCI32
|
#ifdef ENABLE_SCI32
|
||||||
case kResVersionSci32:
|
case kResVersionSci32:
|
||||||
type = (ResourceType)(file->readByte() & 0x7F);
|
type = _resMan->convertResType(file->readByte());
|
||||||
number = file->readUint16LE();
|
number = file->readUint16LE();
|
||||||
szPacked = file->readUint32LE();
|
szPacked = file->readUint32LE();
|
||||||
szUnpacked = file->readUint32LE();
|
szUnpacked = file->readUint32LE();
|
||||||
|
@ -193,6 +193,9 @@ class Resource {
|
|||||||
friend class WaveResourceSource;
|
friend class WaveResourceSource;
|
||||||
friend class AudioVolumeResourceSource;
|
friend class AudioVolumeResourceSource;
|
||||||
friend class MacResourceForkResourceSource;
|
friend class MacResourceForkResourceSource;
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
friend class ChunkResourceSource;
|
||||||
|
#endif
|
||||||
|
|
||||||
// NOTE : Currently most member variables lack the underscore prefix and have
|
// NOTE : Currently most member variables lack the underscore prefix and have
|
||||||
// public visibility to let the rest of the engine compile without changes.
|
// public visibility to let the rest of the engine compile without changes.
|
||||||
@ -203,7 +206,7 @@ public:
|
|||||||
uint32 _headerSize;
|
uint32 _headerSize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Resource(ResourceId id);
|
Resource(ResourceManager *resMan, ResourceId id);
|
||||||
~Resource();
|
~Resource();
|
||||||
void unalloc();
|
void unalloc();
|
||||||
|
|
||||||
@ -227,6 +230,7 @@ protected:
|
|||||||
ResourceStatus _status;
|
ResourceStatus _status;
|
||||||
uint16 _lockers; /**< Number of places where this resource was locked */
|
uint16 _lockers; /**< Number of places where this resource was locked */
|
||||||
ResourceSource *_source;
|
ResourceSource *_source;
|
||||||
|
ResourceManager *_resMan;
|
||||||
|
|
||||||
bool loadPatch(Common::SeekableReadStream *file);
|
bool loadPatch(Common::SeekableReadStream *file);
|
||||||
bool loadFromPatchFile();
|
bool loadFromPatchFile();
|
||||||
@ -251,6 +255,9 @@ class ResourceManager {
|
|||||||
friend class ExtAudioMapResourceSource;
|
friend class ExtAudioMapResourceSource;
|
||||||
friend class WaveResourceSource;
|
friend class WaveResourceSource;
|
||||||
friend class MacResourceForkResourceSource;
|
friend class MacResourceForkResourceSource;
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
friend class ChunkResourceSource;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -324,6 +331,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
void addNewGMPatch(SciGameId gameId);
|
void addNewGMPatch(SciGameId gameId);
|
||||||
|
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
/**
|
||||||
|
* Parses all resources from a SCI2.1 chunk resource and adds them to the
|
||||||
|
* resource manager.
|
||||||
|
*/
|
||||||
|
void addResourcesFromChunk(uint16 id);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool detectHires();
|
bool detectHires();
|
||||||
// Detects, if standard font of current game includes extended characters (>0x80)
|
// Detects, if standard font of current game includes extended characters (>0x80)
|
||||||
bool detectFontExtended();
|
bool detectFontExtended();
|
||||||
|
@ -99,7 +99,7 @@ bool Resource::loadFromAudioVolumeSCI11(Common::SeekableReadStream *file) {
|
|||||||
}
|
}
|
||||||
file->seek(-4, SEEK_CUR);
|
file->seek(-4, SEEK_CUR);
|
||||||
|
|
||||||
ResourceType type = (ResourceType)(file->readByte() & 0x7f);
|
ResourceType type = _resMan->convertResType(file->readByte());
|
||||||
if (((getType() == kResourceTypeAudio || getType() == kResourceTypeAudio36) && (type != kResourceTypeAudio))
|
if (((getType() == kResourceTypeAudio || getType() == kResourceTypeAudio36) && (type != kResourceTypeAudio))
|
||||||
|| ((getType() == kResourceTypeSync || getType() == kResourceTypeSync36) && (type != kResourceTypeSync))) {
|
|| ((getType() == kResourceTypeSync || getType() == kResourceTypeSync36) && (type != kResourceTypeSync))) {
|
||||||
warning("Resource type mismatch loading %s", _id.toString().c_str());
|
warning("Resource type mismatch loading %s", _id.toString().c_str());
|
||||||
|
@ -43,7 +43,8 @@ enum ResSourceType {
|
|||||||
kSourceAudioVolume,
|
kSourceAudioVolume,
|
||||||
kSourceExtAudioMap,
|
kSourceExtAudioMap,
|
||||||
kSourceWave,
|
kSourceWave,
|
||||||
kSourceMacResourceFork
|
kSourceMacResourceFork,
|
||||||
|
kSourceChunk
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -188,6 +189,31 @@ public:
|
|||||||
virtual void loadResource(ResourceManager *resMan, Resource *res);
|
virtual void loadResource(ResourceManager *resMan, Resource *res);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads resources from SCI2.1+ chunk resources
|
||||||
|
*/
|
||||||
|
class ChunkResourceSource : public ResourceSource {
|
||||||
|
public:
|
||||||
|
ChunkResourceSource(const Common::String &name, uint16 number);
|
||||||
|
|
||||||
|
virtual void scanSource(ResourceManager *resMan);
|
||||||
|
virtual void loadResource(ResourceManager *resMan, Resource *res);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint16 _number;
|
||||||
|
|
||||||
|
struct ResourceEntry {
|
||||||
|
uint32 offset;
|
||||||
|
uint32 length;
|
||||||
|
};
|
||||||
|
|
||||||
|
Common::HashMap<ResourceId, ResourceEntry, ResourceIdHash> _resMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
} // End of namespace Sci
|
} // End of namespace Sci
|
||||||
|
|
||||||
#endif // SCI_RESOURCE_INTERN_H
|
#endif // SCI_RESOURCE_INTERN_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user