mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 05:38:56 +00:00
refactor resource module:
- struct ResourceContext => class ResourceContext - replace "*alloc","free" with array templates - simplify createContexts routines svn-id: r46254
This commit is contained in:
parent
4fb779dbaf
commit
aa147a2f5a
@ -352,7 +352,7 @@ void Actor::loadFrameList(int frameListResourceId, ActorFrameSequence *&framesPo
|
||||
memoryError("Actor::loadFrameList");
|
||||
}
|
||||
|
||||
MemoryReadStreamEndian readS(resourcePointer, resourceLength, _actorContext->isBigEndian);
|
||||
MemoryReadStreamEndian readS(resourcePointer, resourceLength, _actorContext->isBigEndian());
|
||||
|
||||
for (int i = 0; i < framesCount; i++) {
|
||||
debug(9, "frameType %d", i);
|
||||
|
@ -90,7 +90,7 @@ void Font::loadFont(uint32 fontResourceId) {
|
||||
error("Font::loadFont() Invalid font length (%i < %i)", (int)fontResourceLength, FONT_DESCSIZE);
|
||||
}
|
||||
|
||||
MemoryReadStreamEndian readS(fontResourcePointer, fontResourceLength, fontContext->isBigEndian);
|
||||
MemoryReadStreamEndian readS(fontResourcePointer, fontResourceLength, fontContext->isBigEndian());
|
||||
|
||||
// Create new font structure
|
||||
font = (FontData *)malloc(sizeof(*font));
|
||||
|
@ -296,12 +296,12 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
|
||||
// Digital music
|
||||
ResourceData *resData = _digitalMusicContext->getResourceData(resourceId - 9);
|
||||
Common::File *musicFile = _digitalMusicContext->getFile(resData);
|
||||
int offs = (_digitalMusicContext->isCompressed) ? 9 : 0;
|
||||
int offs = (_digitalMusicContext->isCompressed()) ? 9 : 0;
|
||||
|
||||
Common::SeekableSubReadStream *musicStream = new Common::SeekableSubReadStream(musicFile,
|
||||
(uint32)resData->offset + offs, (uint32)resData->offset + resData->size - offs);
|
||||
|
||||
if (!_digitalMusicContext->isCompressed) {
|
||||
if (!_digitalMusicContext->isCompressed()) {
|
||||
byte musicFlags = Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_STEREO |
|
||||
Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN;
|
||||
if (flags == MUSIC_LOOP)
|
||||
|
@ -39,21 +39,13 @@
|
||||
|
||||
namespace Saga {
|
||||
|
||||
Resource::Resource(SagaEngine *vm): _vm(vm) {
|
||||
_contexts = NULL;
|
||||
_contextsCount = 0;
|
||||
}
|
||||
|
||||
Resource::~Resource() {
|
||||
clearContexts();
|
||||
}
|
||||
|
||||
bool Resource::loadResContext_v1(ResourceContext *context, uint32 contextOffset, uint32 contextSize) {
|
||||
bool ResourceContext::loadResV1(uint32 contextOffset, uint32 contextSize) {
|
||||
size_t i;
|
||||
bool result;
|
||||
byte tableInfo[RSC_TABLEINFO_SIZE];
|
||||
byte *tableBuffer;
|
||||
size_t tableSize;
|
||||
uint32 count;
|
||||
uint32 resourceTableOffset;
|
||||
ResourceData *resourceData;
|
||||
|
||||
@ -61,41 +53,41 @@ bool Resource::loadResContext_v1(ResourceContext *context, uint32 contextOffset,
|
||||
return false;
|
||||
}
|
||||
|
||||
context->file->seek(contextOffset + contextSize - RSC_TABLEINFO_SIZE);
|
||||
_file.seek(contextOffset + contextSize - RSC_TABLEINFO_SIZE);
|
||||
|
||||
if (context->file->read(tableInfo, RSC_TABLEINFO_SIZE) != RSC_TABLEINFO_SIZE) {
|
||||
if (_file.read(tableInfo, RSC_TABLEINFO_SIZE) != RSC_TABLEINFO_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MemoryReadStreamEndian readS(tableInfo, RSC_TABLEINFO_SIZE, context->isBigEndian);
|
||||
MemoryReadStreamEndian readS(tableInfo, RSC_TABLEINFO_SIZE, _isBigEndian);
|
||||
|
||||
resourceTableOffset = readS.readUint32();
|
||||
context->count = readS.readUint32();
|
||||
count = readS.readUint32();
|
||||
|
||||
// Check for sane table offset
|
||||
if (resourceTableOffset != contextSize - RSC_TABLEINFO_SIZE - RSC_TABLEENTRY_SIZE * context->count) {
|
||||
if (resourceTableOffset != contextSize - RSC_TABLEINFO_SIZE - RSC_TABLEENTRY_SIZE * count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load resource table
|
||||
tableSize = RSC_TABLEENTRY_SIZE * context->count;
|
||||
tableSize = RSC_TABLEENTRY_SIZE * count;
|
||||
|
||||
tableBuffer = (byte *)malloc(tableSize);
|
||||
|
||||
context->file->seek(resourceTableOffset + contextOffset, SEEK_SET);
|
||||
_file.seek(resourceTableOffset + contextOffset, SEEK_SET);
|
||||
|
||||
result = (context->file->read(tableBuffer, tableSize) == tableSize);
|
||||
result = (_file.read(tableBuffer, tableSize) == tableSize);
|
||||
if (result) {
|
||||
context->table = (ResourceData *)calloc(context->count, sizeof(*context->table));
|
||||
_table.resize(count);
|
||||
|
||||
MemoryReadStreamEndian readS1(tableBuffer, tableSize, context->isBigEndian);
|
||||
MemoryReadStreamEndian readS1(tableBuffer, tableSize, _isBigEndian);
|
||||
|
||||
for (i = 0; i < context->count; i++) {
|
||||
resourceData = &context->table[i];
|
||||
for (i = 0; i < count; i++) {
|
||||
resourceData = &_table[i];
|
||||
resourceData->offset = contextOffset + readS1.readUint32();
|
||||
resourceData->size = readS1.readUint32();
|
||||
//sanity check
|
||||
if ((resourceData->offset > (uint)context->fileSize) || (resourceData->size > contextSize)) {
|
||||
if ((resourceData->offset > (uint)_fileSize) || (resourceData->size > contextSize)) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
@ -106,7 +98,7 @@ bool Resource::loadResContext_v1(ResourceContext *context, uint32 contextOffset,
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Resource::loadContext(ResourceContext *context) {
|
||||
bool ResourceContext::load(SagaEngine *vm, Resource *resource) {
|
||||
size_t i;
|
||||
const GamePatchDescription *patchDescription;
|
||||
ResourceData *resourceData;
|
||||
@ -119,45 +111,49 @@ bool Resource::loadContext(ResourceContext *context) {
|
||||
size_t tableSize;
|
||||
bool isMacBinary;
|
||||
|
||||
if (!context->file->open(context->fileName)) {
|
||||
if (_fileName == NULL) { // IHNM special case
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!_file.open(_fileName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
context->fileSize = context->file->size();
|
||||
context->isBigEndian = _vm->isBigEndian();
|
||||
_fileSize = _file.size();
|
||||
_isBigEndian = vm->isBigEndian();
|
||||
|
||||
if (context->fileType & GAME_SWAPENDIAN)
|
||||
context->isBigEndian = !context->isBigEndian;
|
||||
if (_fileType & GAME_SWAPENDIAN)
|
||||
_isBigEndian = !_isBigEndian;
|
||||
|
||||
isMacBinary = (context->fileType & GAME_MACBINARY) > 0;
|
||||
context->fileType &= ~GAME_MACBINARY;
|
||||
isMacBinary = (_fileType & GAME_MACBINARY) > 0;
|
||||
_fileType &= ~GAME_MACBINARY;
|
||||
|
||||
if (!isMacBinary) {
|
||||
if (!loadResContext(context, 0, context->fileSize)) {
|
||||
if (!loadRes(0, _fileSize)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!loadMacContext(context)) {
|
||||
if (!loadMac()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//process internal patch files
|
||||
if (context->fileType & GAME_PATCHFILE) {
|
||||
subjectResourceType = ~GAME_PATCHFILE & context->fileType;
|
||||
subjectContext = getContext((GameFileTypes)subjectResourceType);
|
||||
if (_fileType & GAME_PATCHFILE) {
|
||||
subjectResourceType = ~GAME_PATCHFILE & _fileType;
|
||||
subjectContext = resource->getContext((GameFileTypes)subjectResourceType);
|
||||
if (subjectContext == NULL) {
|
||||
error("Resource::loadContext() Subject context not found");
|
||||
error("ResourceContext::load() Subject context not found");
|
||||
}
|
||||
loadResource(context, context->count - 1, tableBuffer, tableSize);
|
||||
resource->loadResource(this, _table.size() - 1, tableBuffer, tableSize);
|
||||
|
||||
MemoryReadStreamEndian readS2(tableBuffer, tableSize, context->isBigEndian);
|
||||
MemoryReadStreamEndian readS2(tableBuffer, tableSize, _isBigEndian);
|
||||
for (i = 0; i < tableSize / 8; i++) {
|
||||
subjectResourceId = readS2.readUint32();
|
||||
patchResourceId = readS2.readUint32();
|
||||
subjectResourceData = subjectContext->getResourceData(subjectResourceId);
|
||||
resourceData = context->getResourceData(patchResourceId);
|
||||
subjectResourceData->patchData = new PatchData(context->file);
|
||||
resourceData = getResourceData(patchResourceId);
|
||||
subjectResourceData->patchData = new PatchData(&_file);
|
||||
subjectResourceData->offset = resourceData->offset;
|
||||
subjectResourceData->size = resourceData->size;
|
||||
}
|
||||
@ -165,10 +161,10 @@ bool Resource::loadContext(ResourceContext *context) {
|
||||
}
|
||||
|
||||
//process external patch files
|
||||
for (patchDescription = _vm->getPatchDescriptions(); patchDescription && patchDescription->fileName; ++patchDescription) {
|
||||
if ((patchDescription->fileType & context->fileType) != 0) {
|
||||
if (patchDescription->resourceId < context->count) {
|
||||
resourceData = &context->table[patchDescription->resourceId];
|
||||
for (patchDescription = vm->getPatchDescriptions(); patchDescription && patchDescription->fileName; ++patchDescription) {
|
||||
if ((patchDescription->fileType & _fileType) != 0) {
|
||||
if (patchDescription->resourceId < _table.size()) {
|
||||
resourceData = &_table[patchDescription->resourceId];
|
||||
resourceData->patchData = new PatchData(patchDescription);
|
||||
if (resourceData->patchData->_patchFile->open(patchDescription->fileName)) {
|
||||
resourceData->offset = 0;
|
||||
@ -176,7 +172,7 @@ bool Resource::loadContext(ResourceContext *context) {
|
||||
// ITE uses several patch files which are loaded and then not needed
|
||||
// anymore (as they're in memory), so close them here. IHNM uses only
|
||||
// 1 patch file, which is reused, so don't close it
|
||||
if (_vm->getGameId() == GID_ITE)
|
||||
if (vm->getGameId() == GID_ITE)
|
||||
resourceData->patchData->_patchFile->close();
|
||||
} else {
|
||||
delete resourceData->patchData;
|
||||
@ -189,221 +185,140 @@ bool Resource::loadContext(ResourceContext *context) {
|
||||
// Close the file if it's part of a series of files
|
||||
// This prevents having all voice files open in IHNM for no reason, as each chapter uses
|
||||
// a different voice file
|
||||
if (context->serial > 0)
|
||||
context->file->close();
|
||||
if (_serial > 0)
|
||||
_file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resource::createContexts() {
|
||||
int i;
|
||||
Resource::Resource(SagaEngine *vm): _vm(vm) {
|
||||
}
|
||||
|
||||
Resource::~Resource() {
|
||||
clearContexts();
|
||||
}
|
||||
|
||||
void Resource::addContext(const char *fileName, uint16 fileType, bool isCompressed, int serial) {
|
||||
ResourceContext *context;
|
||||
int soundFileIndex = 0;
|
||||
int voicesFileIndex = 0;
|
||||
bool digitalMusic = false;
|
||||
context = createContext();
|
||||
context->_fileName = fileName;
|
||||
context->_fileType = fileType;
|
||||
context->_isCompressed = isCompressed;
|
||||
context->_serial = serial;
|
||||
_contexts.push_back(context);
|
||||
}
|
||||
|
||||
bool Resource::createContexts() {
|
||||
bool soundFileInArray = false;
|
||||
bool multipleVoices = false;
|
||||
bool censoredVersion = false;
|
||||
bool compressedSounds = false;
|
||||
bool compressedMusic = false;
|
||||
uint16 voiceFileType = GAME_VOICEFILE;
|
||||
bool fileFound = false;
|
||||
int maxFile = 0;
|
||||
|
||||
_vm->_voiceFilesExist = true;
|
||||
|
||||
struct SoundFileInfo {
|
||||
int gameId;
|
||||
char fileName[40];
|
||||
bool isCompressed;
|
||||
uint16 voiceFileAddType;
|
||||
};
|
||||
|
||||
SoundFileInfo *curSoundfiles = 0;
|
||||
|
||||
// If the Wyrmkeep credits file is found, set the Wyrmkeep version flag to true
|
||||
if (Common::File::exists("graphics/credit3n.dlt")) {
|
||||
_vm->_gf_wyrmkeep = true;
|
||||
}
|
||||
|
||||
_contextsCount = 0;
|
||||
for (i = 0; _vm->getFilesDescriptions()[i].fileName; i++) {
|
||||
_contextsCount++;
|
||||
if (_vm->getFilesDescriptions()[i].fileType == GAME_SOUNDFILE)
|
||||
for (const ADGameFileDescription *gameFileDescription = _vm->getFilesDescriptions();
|
||||
gameFileDescription->fileName; gameFileDescription++) {
|
||||
addContext(gameFileDescription->fileName, gameFileDescription->fileType);
|
||||
if (gameFileDescription->fileType == GAME_SOUNDFILE) {
|
||||
soundFileInArray = true;
|
||||
}
|
||||
}
|
||||
|
||||
//// Detect and add SFX files ////////////////////////////////////////////////
|
||||
SoundFileInfo sfxFilesITE[] = {
|
||||
{ "sounds.rsc", false },
|
||||
{ "sounds.cmp", true },
|
||||
{ "soundsd.rsc", false },
|
||||
{ "soundsd.cmp", true }
|
||||
};
|
||||
|
||||
SoundFileInfo sfxFiles[] = {
|
||||
{ GID_ITE, "sounds.rsc", false },
|
||||
{ GID_ITE, "sounds.cmp", true },
|
||||
{ GID_ITE, "soundsd.rsc", false },
|
||||
{ GID_ITE, "soundsd.cmp", true },
|
||||
#ifdef ENABLE_IHNM
|
||||
SoundFileInfo sfxFilesIHNM[] = {
|
||||
{ "sfx.res", false },
|
||||
{ "sfx.cmp", true }
|
||||
};
|
||||
{ GID_IHNM, "sfx.res", false },
|
||||
{ GID_IHNM, "sfx.cmp", true },
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SAGA2
|
||||
SoundFileInfo sfxFilesFTA2[] = {
|
||||
{ "ftasound.hrs", false }
|
||||
};
|
||||
|
||||
SoundFileInfo sfxFilesDino[] = {
|
||||
{ "dinosnd.hrs", false },
|
||||
};
|
||||
{ GID_FTA2, "ftasound.hrs", false },
|
||||
{ GID_DINO, "dinosnd.hrs", false },
|
||||
#endif
|
||||
{ -1, NULL, false }
|
||||
};
|
||||
|
||||
_soundFileName[0] = 0;
|
||||
if (!soundFileInArray) {
|
||||
// If the sound file is not specified in the detector table, add it here
|
||||
fileFound = false;
|
||||
|
||||
switch (_vm->getGameId()) {
|
||||
case GID_ITE:
|
||||
curSoundfiles = sfxFilesITE;
|
||||
maxFile = 4;
|
||||
break;
|
||||
#ifdef ENABLE_IHNM
|
||||
case GID_IHNM:
|
||||
curSoundfiles = sfxFilesIHNM;
|
||||
maxFile = 2;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_SAGA2
|
||||
case GID_DINO:
|
||||
curSoundfiles = sfxFilesDino;
|
||||
maxFile = 1;
|
||||
break;
|
||||
case GID_FTA2:
|
||||
curSoundfiles = sfxFilesFTA2;
|
||||
maxFile = 1;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i < maxFile; i++) {
|
||||
if (Common::File::exists(curSoundfiles[i].fileName)) {
|
||||
_contextsCount++;
|
||||
soundFileIndex = _contextsCount - 1;
|
||||
strcpy(_soundFileName, curSoundfiles[i].fileName);
|
||||
compressedSounds = curSoundfiles[i].isCompressed;
|
||||
fileFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fileFound) {
|
||||
// No sound file found, don't add any file to the array
|
||||
soundFileInArray = true;
|
||||
if (_vm->getGameId() == GID_ITE) {
|
||||
// ITE floppy versions have both voices and sounds in voices.rsc
|
||||
voiceFileType = GAME_SOUNDFILE | GAME_VOICEFILE;
|
||||
}
|
||||
for (SoundFileInfo *curSoundFile = sfxFiles; (curSoundFile->gameId != -1); curSoundFile++) {
|
||||
if (curSoundFile->gameId != _vm->getGameId()) continue;
|
||||
if (!Common::File::exists(curSoundFile->fileName)) continue;
|
||||
strcpy(_soundFileName, curSoundFile->fileName);
|
||||
addContext(_soundFileName, GAME_SOUNDFILE, curSoundFile->isCompressed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//// Detect and add voice files /////////////////////////////////////////////
|
||||
SoundFileInfo voiceFilesITE[] = {
|
||||
{ "voices.rsc", false },
|
||||
{ "voices.cmp", true },
|
||||
{ "voicesd.rsc", false },
|
||||
{ "voicesd.cmp", true },
|
||||
{ "inherit the earth voices", false },
|
||||
{ "inherit the earth voices.cmp", true },
|
||||
{ "ite voices.bin", false }
|
||||
};
|
||||
|
||||
SoundFileInfo voiceFiles[] = {
|
||||
{ GID_ITE, "voices.rsc", false , (_soundFileName[0] == 0) ? GAME_SOUNDFILE : 0},
|
||||
{ GID_ITE, "voices.cmp", true , (_soundFileName[0] == 0) ? GAME_SOUNDFILE : 0},
|
||||
{ GID_ITE, "voicesd.rsc", false , (_soundFileName[0] == 0) ? GAME_SOUNDFILE : 0},
|
||||
{ GID_ITE, "voicesd.cmp", true , (_soundFileName[0] == 0) ? GAME_SOUNDFILE : 0},
|
||||
// The resources in the Wyrmkeep combined Windows/Mac/Linux CD version are little endian, but
|
||||
// the voice file is big endian. If we got such a version with mixed files, mark this voice file
|
||||
// as big endian
|
||||
{ GID_ITE, "inherit the earth voices", false , _vm->isBigEndian() ? 0 : GAME_SWAPENDIAN},
|
||||
{ GID_ITE, "inherit the earth voices.cmp", true , _vm->isBigEndian() ? 0 : GAME_SWAPENDIAN},
|
||||
{ GID_ITE, "ite voices.bin", false , GAME_MACBINARY},
|
||||
#ifdef ENABLE_IHNM
|
||||
SoundFileInfo voiceFilesIHNM[] = {
|
||||
{ "voicess.res", false },
|
||||
{ "voicess.cmp", true },
|
||||
{ "voicesd.res", false },
|
||||
{ "voicesd.cmp", true },
|
||||
};
|
||||
{ GID_IHNM, "voicess.res", false , 0},
|
||||
{ GID_IHNM, "voicess.cmp", true , 0},
|
||||
{ GID_IHNM, "voicesd.res", false , 0},
|
||||
{ GID_IHNM, "voicesd.cmp", true , 0},
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SAGA2
|
||||
SoundFileInfo voiceFilesFTA2[] = {
|
||||
{ "ftavoice.hrs", false },
|
||||
};
|
||||
{ GID_FTA2, "ftavoice.hrs", false , 0},
|
||||
#endif
|
||||
{ -1, NULL, false , 0}
|
||||
};
|
||||
|
||||
// Detect and add voice files
|
||||
fileFound = false;
|
||||
_voicesFileName[0][0] = 0;
|
||||
for (SoundFileInfo *curSoundFile = voiceFiles; (curSoundFile->gameId != -1); curSoundFile++) {
|
||||
if (curSoundFile->gameId != _vm->getGameId()) continue;
|
||||
if (!Common::File::exists(curSoundFile->fileName)) continue;
|
||||
|
||||
switch (_vm->getGameId()) {
|
||||
case GID_ITE:
|
||||
curSoundfiles = voiceFilesITE;
|
||||
maxFile = 7;
|
||||
break;
|
||||
#ifdef ENABLE_IHNM
|
||||
case GID_IHNM:
|
||||
curSoundfiles = voiceFilesIHNM;
|
||||
maxFile = 4;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_SAGA2
|
||||
/*
|
||||
case GID_DINO:
|
||||
// TODO
|
||||
curSoundfiles = NULL;
|
||||
maxFile = 0;
|
||||
break;
|
||||
*/
|
||||
case GID_FTA2:
|
||||
curSoundfiles = voiceFilesFTA2;
|
||||
maxFile = 1;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
strcpy(_voicesFileName[0], curSoundFile->fileName);
|
||||
addContext(_voicesFileName[0], GAME_VOICEFILE | curSoundFile->voiceFileAddType, curSoundFile->isCompressed);
|
||||
|
||||
for (i = 0; i < maxFile; i++) {
|
||||
if (Common::File::exists(curSoundfiles[i].fileName)) {
|
||||
_contextsCount++;
|
||||
voicesFileIndex = _contextsCount - 1;
|
||||
strcpy(_voicesFileName[0], curSoundfiles[i].fileName);
|
||||
compressedSounds = curSoundfiles[i].isCompressed;
|
||||
fileFound = true;
|
||||
|
||||
// Special cases
|
||||
if (!scumm_stricmp(curSoundfiles[i].fileName, "inherit the earth voices") ||
|
||||
!scumm_stricmp(curSoundfiles[i].fileName, "inherit the earth voices.cmp")) {
|
||||
// The resources in the Wyrmkeep combined Windows/Mac/Linux CD version are little endian, but
|
||||
// the voice file is big endian. If we got such a version with mixed files, mark this voice file
|
||||
// as big endian
|
||||
if (!_vm->isBigEndian())
|
||||
voiceFileType = GAME_VOICEFILE | GAME_SWAPENDIAN; // This file is big endian
|
||||
}
|
||||
|
||||
if (!scumm_stricmp(curSoundfiles[i].fileName, "ite voices.bin")) {
|
||||
voiceFileType = GAME_VOICEFILE | GAME_MACBINARY;
|
||||
}
|
||||
|
||||
if (!scumm_stricmp(curSoundfiles[i].fileName, "voicess.res") ||
|
||||
!scumm_stricmp(curSoundfiles[i].fileName, "voicess.cmp")) {
|
||||
// Special cases
|
||||
if (!scumm_stricmp(curSoundFile->fileName, "voicess.res") ||
|
||||
!scumm_stricmp(curSoundFile->fileName, "voicess.cmp")) {
|
||||
// IHNM has multiple voice files
|
||||
multipleVoices = true;
|
||||
// Note: it is assumed that the voice files are always last in the list
|
||||
if (Common::File::exists("voices4.res") || Common::File::exists("voices4.cmp")) {
|
||||
_contextsCount += 6; // voices1-voices6
|
||||
} else {
|
||||
// The German and French versions of IHNM don't have Nimdok's chapter,
|
||||
// therefore the voices file for that chapter is missing
|
||||
_contextsCount += 5; // voices1-voices3, voices4-voices5
|
||||
censoredVersion = true;
|
||||
for (size_t i = 1; i <= 6; i++) { // voices1-voices6
|
||||
sprintf(_voicesFileName[i], "voices%i.%s", i, curSoundFile->isCompressed ? "cmp" : "res");
|
||||
if (i == 4) {
|
||||
// The German and French versions of IHNM don't have Nimdok's chapter,
|
||||
// therefore the voices file for that chapter is missing
|
||||
if (!Common::File::exists(_voicesFileName[i])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
addContext(_voicesFileName[i], GAME_VOICEFILE, curSoundFile->isCompressed, i);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fileFound) {
|
||||
if (_voicesFileName[0][0] == 0) {
|
||||
if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
|
||||
// The Macintosh version of IHNM has no voices.res, and it has all
|
||||
// its voice files in subdirectories, so don't do anything here
|
||||
_contexts.push_back(new VoiceResourceContext_RES());
|
||||
} else {
|
||||
warning("No voice file found, voices will be disabled");
|
||||
_vm->_voicesEnabled = false;
|
||||
@ -412,83 +327,27 @@ bool Resource::createContexts() {
|
||||
}
|
||||
}
|
||||
|
||||
//// Detect and add ITE music files /////////////////////////////////////////
|
||||
SoundFileInfo musicFilesITE[] = {
|
||||
{ "music.rsc", false },
|
||||
{ "music.cmp", true },
|
||||
{ "musicd.rsc", false },
|
||||
{ "musicd.cmp", true },
|
||||
//// Detect and add music files /////////////////////////////////////////
|
||||
SoundFileInfo musicFiles[] = {
|
||||
{ GID_ITE, "music.rsc", false },
|
||||
{ GID_ITE, "music.cmp", true },
|
||||
{ GID_ITE, "musicd.rsc", false },
|
||||
{ GID_ITE, "musicd.cmp", true },
|
||||
{ -1, NULL, false }
|
||||
};
|
||||
|
||||
// Check for digital music in ITE
|
||||
if (_vm->getGameId() == GID_ITE) {
|
||||
fileFound = false;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (Common::File::exists(musicFilesITE[i].fileName)) {
|
||||
_contextsCount++;
|
||||
digitalMusic = true;
|
||||
compressedMusic = musicFilesITE[i].isCompressed;
|
||||
fileFound = true;
|
||||
strcpy(_musicFileName, musicFilesITE[i].fileName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fileFound) {
|
||||
// No sound file found, don't add any file to the array
|
||||
digitalMusic = false;
|
||||
}
|
||||
for (SoundFileInfo *curSoundFile = musicFiles; (curSoundFile->gameId != -1); curSoundFile++) {
|
||||
if (curSoundFile->gameId != _vm->getGameId()) continue;
|
||||
if (!Common::File::exists(curSoundFile->fileName)) continue;
|
||||
strcpy(_musicFileName, curSoundFile->fileName);
|
||||
addContext(_musicFileName, GAME_DIGITALMUSICFILE, curSoundFile->isCompressed);
|
||||
break;
|
||||
}
|
||||
|
||||
_contexts = (ResourceContext*)calloc(_contextsCount, sizeof(*_contexts));
|
||||
|
||||
for (i = 0; i < _contextsCount; i++) {
|
||||
context = &_contexts[i];
|
||||
context->file = new Common::File();
|
||||
context->serial = 0;
|
||||
|
||||
// For ITE, add the digital music file and sfx file information here
|
||||
if (_vm->getGameId() == GID_ITE && digitalMusic && i == _contextsCount - 1) {
|
||||
context->fileName = _musicFileName;
|
||||
context->fileType = GAME_DIGITALMUSICFILE;
|
||||
context->isCompressed = compressedMusic;
|
||||
} else if (!soundFileInArray && i == soundFileIndex) {
|
||||
context->fileName = _soundFileName;
|
||||
context->fileType = GAME_SOUNDFILE;
|
||||
context->isCompressed = compressedSounds;
|
||||
} else if (_vm->_voiceFilesExist && i == voicesFileIndex && !(_vm->getGameId() == GID_IHNM && _vm->isMacResources())) {
|
||||
context->fileName = _voicesFileName[0];
|
||||
// can be GAME_VOICEFILE or GAME_SOUNDFILE | GAME_VOICEFILE or GAME_VOICEFILE | GAME_SWAPENDIAN
|
||||
context->fileType = voiceFileType;
|
||||
context->isCompressed = compressedSounds;
|
||||
} else {
|
||||
if (!(_vm->_voiceFilesExist && multipleVoices && (i > voicesFileIndex))) {
|
||||
context->fileName = _vm->getFilesDescriptions()[i].fileName;
|
||||
context->fileType = _vm->getFilesDescriptions()[i].fileType;
|
||||
context->isCompressed = compressedSounds;
|
||||
} else {
|
||||
int token = (censoredVersion && (i - voicesFileIndex >= 4)) ? 1 : 0; // censored versions don't have voice4
|
||||
|
||||
if (compressedSounds)
|
||||
sprintf(_voicesFileName[i - voicesFileIndex + token], "voices%i.cmp", i - voicesFileIndex + token);
|
||||
else
|
||||
sprintf(_voicesFileName[i - voicesFileIndex + token], "voices%i.res", i - voicesFileIndex + token);
|
||||
|
||||
context->fileName = _voicesFileName[i - voicesFileIndex + token];
|
||||
context->fileType = GAME_VOICEFILE;
|
||||
context->isCompressed = compressedSounds;
|
||||
|
||||
// IHNM has several different voice files, so we need to allow
|
||||
// multiple resource contexts of the same type. We tell them
|
||||
// apart by assigning each of the duplicates a unique serial
|
||||
// number. The default behaviour when requesting a context will
|
||||
// be to look for serial number 0.
|
||||
context->serial = i - voicesFileIndex + token;
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadContext(context)) {
|
||||
for (ResourceContextList::iterator i = _contexts.begin(); i != _contexts.end(); ++i) {
|
||||
if (!(*i)->load(_vm, this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -496,27 +355,12 @@ bool Resource::createContexts() {
|
||||
}
|
||||
|
||||
void Resource::clearContexts() {
|
||||
int i;
|
||||
size_t j;
|
||||
ResourceContext *context;
|
||||
if (_contexts == NULL) {
|
||||
return;
|
||||
ResourceContextList::iterator i = _contexts.begin();
|
||||
while (i != _contexts.end()) {
|
||||
ResourceContext * context = *i;
|
||||
i = _contexts.erase(i);
|
||||
delete context;
|
||||
}
|
||||
for (i = 0; i < _contextsCount; i++) {
|
||||
context = &_contexts[i];
|
||||
delete context->file;
|
||||
if (context->table != NULL) {
|
||||
for (j = 0; j < context->count; j++) {
|
||||
delete context->table[j].patchData;
|
||||
}
|
||||
}
|
||||
if (_vm->isSaga2()) {
|
||||
free(context->categories);
|
||||
}
|
||||
free(context->table);
|
||||
}
|
||||
free(_contexts);
|
||||
_contexts = NULL;
|
||||
}
|
||||
|
||||
void Resource::loadResource(ResourceContext *context, uint32 resourceId, byte*&resourceBuffer, size_t &resourceSize) {
|
||||
@ -548,4 +392,14 @@ void Resource::loadResource(ResourceContext *context, uint32 resourceId, byte*&r
|
||||
file->close();
|
||||
}
|
||||
|
||||
ResourceContext *Resource::getContext(uint16 fileType, int serial) {
|
||||
for (ResourceContextList::const_iterator i = _contexts.begin(); i != _contexts.end(); ++i) {
|
||||
ResourceContext * context = *i;
|
||||
if ((context->fileType() & fileType) && (context->serial() == serial)) {
|
||||
return context;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // End of namespace Saga
|
||||
|
@ -62,53 +62,111 @@ struct ResourceData {
|
||||
size_t size;
|
||||
PatchData *patchData;
|
||||
|
||||
bool isExternal() { return ((offset & (1L<<31)) != 0L); } // SAGA2
|
||||
ResourceData() :
|
||||
id(0), offset(0), size(0), patchData(NULL) {
|
||||
}
|
||||
|
||||
~ResourceData() {
|
||||
if (patchData) {
|
||||
delete patchData;
|
||||
patchData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool isExternal() { // SAGA2
|
||||
return ((offset & (1L<<31)) != 0L);
|
||||
}
|
||||
};
|
||||
|
||||
struct ResourceContext {
|
||||
const char *fileName;
|
||||
uint16 fileType;
|
||||
Common::File *file;
|
||||
int32 fileSize;
|
||||
int serial; // IHNM speech files
|
||||
class ResourceDataArray : public Common::Array<ResourceData> {
|
||||
};
|
||||
|
||||
bool isCompressed;
|
||||
bool isBigEndian;
|
||||
ResourceData *table;
|
||||
size_t count;
|
||||
ResourceData *categories; // SAGA2
|
||||
class ResourceContext {
|
||||
friend class Resource;
|
||||
protected:
|
||||
const char *_fileName;
|
||||
uint16 _fileType;
|
||||
bool _isCompressed;
|
||||
int _serial; // IHNM speech files
|
||||
|
||||
Common::File *getFile(ResourceData *resourceData) const {
|
||||
if (resourceData->patchData != NULL) {
|
||||
if (!resourceData->patchData->_patchFile->isOpen())
|
||||
resourceData->patchData->_patchFile->open(resourceData->patchData->_patchDescription->fileName);
|
||||
return resourceData->patchData->_patchFile;
|
||||
bool _isBigEndian;
|
||||
ResourceDataArray _table;
|
||||
Common::File _file;
|
||||
int32 _fileSize;
|
||||
|
||||
bool load(SagaEngine *_vm, Resource *resource);
|
||||
bool loadResV1(uint32 contextOffset, uint32 contextSize);
|
||||
|
||||
virtual bool loadMac() = 0;
|
||||
virtual bool loadRes(uint32 contextOffset, uint32 contextSize) = 0;
|
||||
public:
|
||||
|
||||
ResourceContext():
|
||||
_fileName(NULL), _fileType(0), _isCompressed(false), _serial(0),
|
||||
_isBigEndian(false),
|
||||
_fileSize(0) {
|
||||
}
|
||||
|
||||
bool isCompressed() const {
|
||||
return _isCompressed;
|
||||
}
|
||||
|
||||
uint16 fileType() const {
|
||||
return _fileType;
|
||||
}
|
||||
|
||||
int serial() const {
|
||||
return _serial;
|
||||
}
|
||||
|
||||
bool isBigEndian() const {
|
||||
return _isBigEndian;
|
||||
}
|
||||
|
||||
const char * fileName() const {
|
||||
return _fileName;
|
||||
}
|
||||
|
||||
Common::File *getFile(ResourceData *resourceData) {
|
||||
Common::File *file;
|
||||
const char * fn;
|
||||
if (resourceData && resourceData->patchData != NULL) {
|
||||
file = resourceData->patchData->_patchFile;
|
||||
fn = resourceData->patchData->_patchDescription->fileName;
|
||||
} else {
|
||||
return file;
|
||||
file = &_file;
|
||||
fn = _fileName;
|
||||
}
|
||||
if (!file->isOpen())
|
||||
file->open(fn);
|
||||
return file;
|
||||
}
|
||||
|
||||
bool validResourceId(uint32 resourceId) const {
|
||||
return (resourceId < count);
|
||||
return (resourceId < _table.size());
|
||||
}
|
||||
|
||||
ResourceData *getResourceData(uint32 resourceId) const {
|
||||
if (resourceId >= count) {
|
||||
ResourceData *getResourceData(uint32 resourceId) {
|
||||
if (resourceId >= _table.size()) {
|
||||
error("ResourceContext::getResourceData() wrong resourceId %d", resourceId);
|
||||
}
|
||||
return &table[resourceId];
|
||||
return &_table[resourceId];
|
||||
}
|
||||
|
||||
// SAGA 2
|
||||
int32 getEntryNum(uint32 id) {
|
||||
for (int32 i = 0; i < (int32)count; i++) {
|
||||
if (table[i].id == id) {
|
||||
return i;
|
||||
int32 num = 0;
|
||||
for (ResourceDataArray::const_iterator i = _table.begin(); i != _table.end(); ++i) {
|
||||
if (i->id == id) {
|
||||
return num;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
class ResourceContextList : public Common::List<ResourceContext*> {
|
||||
};
|
||||
|
||||
struct MetaResource {
|
||||
@ -145,32 +203,29 @@ public:
|
||||
virtual uint32 convertResourceId(uint32 resourceId) = 0;
|
||||
virtual void loadGlobalResources(int chapter, int actorsEntrance) = 0;
|
||||
|
||||
ResourceContext *getContext(uint16 fileType, int serial = 0) {
|
||||
for (int i = 0; i < _contextsCount; i++) {
|
||||
if ((_contexts[i].fileType & fileType) && _contexts[i].serial == serial) {
|
||||
return &_contexts[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ResourceContext *getContext(uint16 fileType, int serial = 0);
|
||||
protected:
|
||||
SagaEngine *_vm;
|
||||
ResourceContext *_contexts;
|
||||
int _contextsCount;
|
||||
ResourceContextList _contexts;
|
||||
char _voicesFileName[8][256];
|
||||
char _musicFileName[256];
|
||||
char _soundFileName[256];
|
||||
|
||||
bool loadContext(ResourceContext *context);
|
||||
virtual bool loadMacContext(ResourceContext *context) = 0;
|
||||
virtual bool loadResContext(ResourceContext *context, uint32 contextOffset, uint32 contextSize) = 0;
|
||||
bool loadResContext_v1(ResourceContext *context, uint32 contextOffset, uint32 contextSize);
|
||||
void addContext(const char *fileName, uint16 fileType, bool isCompressed = false, int serial = 0);
|
||||
virtual ResourceContext *createContext() = 0;
|
||||
public:
|
||||
virtual MetaResource* getMetaResource() = 0;
|
||||
};
|
||||
|
||||
// ITE
|
||||
class ResourceContext_RSC: public ResourceContext {
|
||||
protected:
|
||||
virtual bool loadMac();
|
||||
virtual bool loadRes(uint32 contextOffset, uint32 contextSize) {
|
||||
return loadResV1(contextOffset, contextSize);
|
||||
}
|
||||
};
|
||||
|
||||
class Resource_RSC : public Resource {
|
||||
public:
|
||||
Resource_RSC(SagaEngine *vm) : Resource(vm) {}
|
||||
@ -180,32 +235,70 @@ public:
|
||||
MetaResource *dummy = 0;
|
||||
return dummy;
|
||||
}
|
||||
private:
|
||||
virtual bool loadMacContext(ResourceContext *context);
|
||||
virtual bool loadResContext(ResourceContext *context, uint32 contextOffset, uint32 contextSize) {
|
||||
return loadResContext_v1(context, contextOffset, contextSize);
|
||||
protected:
|
||||
virtual ResourceContext *createContext() {
|
||||
return new ResourceContext_RSC();
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef ENABLE_IHNM
|
||||
// IHNM
|
||||
class ResourceContext_RES: public ResourceContext {
|
||||
protected:
|
||||
virtual bool loadMac() {
|
||||
return false;
|
||||
}
|
||||
virtual bool loadRes(uint32 contextOffset, uint32 contextSize) {
|
||||
return loadResV1(0, contextSize);
|
||||
}
|
||||
};
|
||||
|
||||
//TODO: move load routines from sndres
|
||||
class VoiceResourceContext_RES: public ResourceContext {
|
||||
protected:
|
||||
virtual bool loadMac() {
|
||||
return false;
|
||||
}
|
||||
virtual bool loadRes(uint32 contextOffset, uint32 contextSize) {
|
||||
return false;
|
||||
}
|
||||
public:
|
||||
VoiceResourceContext_RES() : ResourceContext() {
|
||||
_fileType = GAME_VOICEFILE;
|
||||
_isBigEndian = true;
|
||||
}
|
||||
};
|
||||
|
||||
class Resource_RES : public Resource {
|
||||
public:
|
||||
Resource_RES(SagaEngine *vm) : Resource(vm) {}
|
||||
virtual uint32 convertResourceId(uint32 resourceId) { return resourceId; }
|
||||
virtual void loadGlobalResources(int chapter, int actorsEntrance);
|
||||
virtual MetaResource* getMetaResource() { return &_metaResource; };
|
||||
private:
|
||||
virtual bool loadMacContext(ResourceContext *context) { return false; }
|
||||
virtual bool loadResContext(ResourceContext *context, uint32 contextOffset, uint32 contextSize) {
|
||||
return loadResContext_v1(context, 0, contextSize);
|
||||
protected:
|
||||
virtual ResourceContext *createContext() {
|
||||
return new ResourceContext_RES();
|
||||
}
|
||||
private:
|
||||
MetaResource _metaResource;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SAGA2
|
||||
// DINO, FTA2
|
||||
class ResourceContext_HRS: public ResourceContext {
|
||||
protected:
|
||||
ResourceDataArray _categories;
|
||||
|
||||
virtual bool loadMac() {
|
||||
return false;
|
||||
}
|
||||
virtual bool loadRes(uint32 contextOffset, uint32 contextSize) {
|
||||
return loadResV2(contextSize);
|
||||
}
|
||||
bool loadResV2(uint32 contextSize);
|
||||
};
|
||||
|
||||
class Resource_HRS : public Resource {
|
||||
public:
|
||||
Resource_HRS(SagaEngine *vm) : Resource(vm) {}
|
||||
@ -215,12 +308,10 @@ public:
|
||||
MetaResource *dummy = 0;
|
||||
return dummy;
|
||||
}
|
||||
private:
|
||||
virtual bool loadMacContext(ResourceContext *context) { return false; }
|
||||
virtual bool loadResContext(ResourceContext *context, uint32 contextOffset, uint32 contextSize) {
|
||||
return loadResContext_v2(context, contextSize);
|
||||
protected:
|
||||
virtual ResourceContext *createContext() {
|
||||
return new ResourceContext_HRS();
|
||||
}
|
||||
bool loadResContext_v2(ResourceContext *context, uint32 contextSize);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -42,64 +42,54 @@
|
||||
|
||||
namespace Saga {
|
||||
|
||||
void readElement(Common::File *file, Saga::ResourceData *element) {
|
||||
element->id = file->readUint32BE();
|
||||
element->offset = file->readUint32LE();
|
||||
element->size = file->readUint32LE();
|
||||
debug(3, "Entry: id %u, offset %u, size %u", element->id, (uint)element->offset, (uint)element->size);
|
||||
void readElement(Common::File &file, Saga::ResourceData &element) {
|
||||
element.id = file.readUint32BE();
|
||||
element.offset = file.readUint32LE();
|
||||
element.size = file.readUint32LE();
|
||||
debug(3, "Entry: id %u, offset %u, size %u", element.id, (uint)element.offset, (uint)element.size);
|
||||
}
|
||||
|
||||
bool Resource_HRS::loadResContext_v2(ResourceContext *context, uint32 contextSize) {
|
||||
ResourceData *origin = new ResourceData();
|
||||
bool ResourceContext_HRS::loadResV2(uint32 contextSize) {
|
||||
ResourceData origin;
|
||||
uint32 firstEntryOffset;
|
||||
uint32 tableSize;
|
||||
int i, count;
|
||||
const uint32 resourceSize = 4 + 4 + 4; // id, size, offset
|
||||
|
||||
debug(3, "Context %s =====", context->fileName);
|
||||
context->file->seek(0, SEEK_SET);
|
||||
debug(3, "Context %s =====", _fileName);
|
||||
_file.seek(0, SEEK_SET);
|
||||
|
||||
readElement(context->file, origin);
|
||||
readElement(_file, origin);
|
||||
|
||||
// Check if the file is valid
|
||||
if (origin->id != MKID_BE('HRES')) { // header
|
||||
delete origin;
|
||||
if (origin.id != MKID_BE('HRES')) { // header
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read offset of first entry
|
||||
context->file->seek(origin->offset - sizeof(uint32), SEEK_SET);
|
||||
firstEntryOffset = context->file->readUint32LE();
|
||||
_file.seek(origin.offset - sizeof(uint32), SEEK_SET);
|
||||
firstEntryOffset = _file.readUint32LE();
|
||||
|
||||
// Allocate buffers for table, categories and data
|
||||
context->categories = (ResourceData *) calloc(origin->size / resourceSize, sizeof(*context->categories));
|
||||
tableSize = origin->offset - firstEntryOffset - sizeof(uint32);
|
||||
context->table = (ResourceData *) calloc(tableSize / resourceSize, sizeof(*context->table));
|
||||
|
||||
if (context->categories == NULL || context->table == NULL) {
|
||||
delete origin;
|
||||
return false;
|
||||
}
|
||||
_categories.resize(origin.size / resourceSize);
|
||||
tableSize = origin.offset - firstEntryOffset - sizeof(uint32);
|
||||
_table.resize(tableSize / resourceSize);
|
||||
|
||||
// Read categories
|
||||
count = origin->size / resourceSize;
|
||||
count = origin.size / resourceSize;
|
||||
debug(3, "Categories: %d =====", count);
|
||||
for (i = 0; i < count; i++) {
|
||||
readElement(context->file, &context->categories[i]);
|
||||
readElement(_file, _categories[i]);
|
||||
}
|
||||
|
||||
context->file->seek(firstEntryOffset, SEEK_SET);
|
||||
_file.seek(firstEntryOffset, SEEK_SET);
|
||||
|
||||
// Read table entries
|
||||
count = tableSize / resourceSize;
|
||||
debug(3, "Entries: %d =====", count);
|
||||
for (i = 0; i < count; i++) {
|
||||
readElement(context->file, &context->table[i]);
|
||||
readElement(_file, _table[i]);
|
||||
}
|
||||
|
||||
context->count = tableSize / resourceSize;
|
||||
|
||||
delete origin;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,12 @@ struct MacResource {
|
||||
byte attr;
|
||||
int32 dataOffset;
|
||||
byte name[255];
|
||||
MacResource() : id(0), nameOffset(0), attr(0), dataOffset(0) {
|
||||
name[0] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class MacResourceArray : public Common::Array<MacResource> {
|
||||
};
|
||||
|
||||
struct MacResType {
|
||||
@ -59,11 +65,135 @@ struct MacResType {
|
||||
int16 items;
|
||||
int16 maxItemId;
|
||||
int16 offset;
|
||||
MacResource *resources;
|
||||
MacResourceArray resources;
|
||||
MacResType() : id(0), items(0), maxItemId(0), offset(0) {
|
||||
}
|
||||
};
|
||||
|
||||
class MacResTypeArray : public Common::Array<MacResType> {
|
||||
};
|
||||
|
||||
#define ID_MIDI MKID_BE('Midi')
|
||||
|
||||
bool ResourceContext_RSC::loadMac() {
|
||||
int32 macDataSize, macDataSizePad;
|
||||
int32 macResSize, macResSizePad;
|
||||
int32 macResOffset;
|
||||
|
||||
uint32 macMapLength;
|
||||
uint32 macDataLength;
|
||||
uint32 macMapOffset;
|
||||
uint32 macDataOffset;
|
||||
|
||||
MacResMap macResMap;
|
||||
MacResTypeArray macResTypes;
|
||||
|
||||
byte macNameLen;
|
||||
bool notSagaContext = false;
|
||||
|
||||
if (_fileSize < RSC_MIN_FILESIZE + MAC_BINARY_HEADER_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_file.readByte() != 0) {
|
||||
return false;
|
||||
}
|
||||
_file.readByte(); //MAX Name Len
|
||||
_file.seek(74);
|
||||
if (_file.readByte() != 0) {
|
||||
return false;
|
||||
}
|
||||
_file.seek(82);
|
||||
if (_file.readByte() != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
macDataSize = _file.readSint32BE();
|
||||
macResSize = _file.readSint32BE();
|
||||
macDataSizePad = (((macDataSize + 127) >> 7) << 7);
|
||||
macResSizePad = (((macResSize + 127) >> 7) << 7);
|
||||
|
||||
macResOffset = MAC_BINARY_HEADER_SIZE + macDataSizePad;
|
||||
_file.seek(macResOffset);
|
||||
|
||||
macDataOffset = _file.readUint32BE() + macResOffset;
|
||||
macMapOffset = _file.readUint32BE() + macResOffset;
|
||||
macDataLength = _file.readUint32BE();
|
||||
macMapLength = _file.readUint32BE();
|
||||
|
||||
if (macDataOffset >= (uint)_fileSize || macMapOffset >= (uint)_fileSize ||
|
||||
macDataLength + macMapLength > (uint)_fileSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_file.seek(macMapOffset + 22);
|
||||
|
||||
macResMap.resAttr = _file.readUint16BE();
|
||||
macResMap.typeOffset = _file.readUint16BE();
|
||||
macResMap.nameOffset = _file.readUint16BE();
|
||||
macResMap.numTypes = _file.readUint16BE();
|
||||
macResMap.numTypes++;
|
||||
|
||||
_file.seek(macMapOffset + macResMap.typeOffset + 2);
|
||||
|
||||
macResTypes.resize(macResMap.numTypes);
|
||||
|
||||
for (MacResTypeArray::iterator k = macResTypes.begin(); k != macResTypes.end(); ++k) {
|
||||
k->id = _file.readUint32BE();
|
||||
k->items = _file.readUint16BE();
|
||||
k->offset = _file.readUint16BE();
|
||||
k->items++;
|
||||
k->resources.resize(k->items);
|
||||
}
|
||||
|
||||
for (MacResTypeArray::iterator k = macResTypes.begin(); k != macResTypes.end(); ++k) {
|
||||
_file.seek(k->offset + macMapOffset + macResMap.typeOffset);
|
||||
|
||||
for (MacResourceArray::iterator j = k->resources.begin(); j != k->resources.end(); ++j) {
|
||||
j->id = _file.readUint16BE();
|
||||
j->nameOffset = _file.readUint16BE();
|
||||
j->dataOffset = _file.readUint32BE();
|
||||
macResSize = _file.readUint32BE();
|
||||
|
||||
j->attr = j->dataOffset >> 24;
|
||||
j->dataOffset &= 0xFFFFFF;
|
||||
if (j->id > k->maxItemId) {
|
||||
k->maxItemId = j->id;
|
||||
}
|
||||
}
|
||||
|
||||
for (MacResourceArray::iterator j = k->resources.begin(); j != k->resources.end(); ++j) {
|
||||
if (j->nameOffset != -1) {
|
||||
_file.seek(j->nameOffset + macMapOffset + macResMap.nameOffset);
|
||||
macNameLen = _file.readByte();
|
||||
_file.read(j->name, macNameLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
for (MacResTypeArray::iterator k = macResTypes.begin(); k != macResTypes.end(); ++k) {
|
||||
//getting offsets & sizes of midi
|
||||
if (((_fileType & GAME_MUSICFILE_GM) > 0) && (k->id == ID_MIDI)) {
|
||||
|
||||
_table.resize(k->maxItemId + 1);
|
||||
for (MacResourceArray::iterator j = k->resources.begin(); j != k->resources.end(); ++j) {
|
||||
_file.seek(macDataOffset + j->dataOffset);
|
||||
_table[j->id].size = _file.readUint32BE();
|
||||
_table[j->id].offset = _file.pos();
|
||||
}
|
||||
notSagaContext = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!notSagaContext) && (!loadRes(MAC_BINARY_HEADER_SIZE, macDataSize))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 Resource_RSC::convertResourceId(uint32 resourceId) {
|
||||
|
||||
if (_vm->isMacResources()) {
|
||||
@ -79,134 +209,4 @@ uint32 Resource_RSC::convertResourceId(uint32 resourceId) {
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
bool Resource_RSC::loadMacContext(ResourceContext *context) {
|
||||
int32 macDataSize, macDataSizePad;
|
||||
int32 macResSize, macResSizePad;
|
||||
int32 macResOffset;
|
||||
|
||||
uint32 macMapLength;
|
||||
uint32 macDataLength;
|
||||
uint32 macMapOffset;
|
||||
uint32 macDataOffset;
|
||||
|
||||
MacResMap macResMap;
|
||||
MacResType *macResTypes;
|
||||
|
||||
MacResType *macResType;
|
||||
MacResource *macResource;
|
||||
int i, j;
|
||||
byte macNameLen;
|
||||
bool notSagaContext = false;
|
||||
|
||||
if (context->fileSize < RSC_MIN_FILESIZE + MAC_BINARY_HEADER_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context->file->readByte() != 0) {
|
||||
return false;
|
||||
}
|
||||
context->file->readByte(); //MAX Name Len
|
||||
context->file->seek(74);
|
||||
if (context->file->readByte() != 0) {
|
||||
return false;
|
||||
}
|
||||
context->file->seek(82);
|
||||
if (context->file->readByte() != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
macDataSize = context->file->readSint32BE();
|
||||
macResSize = context->file->readSint32BE();
|
||||
macDataSizePad = (((macDataSize + 127) >> 7) << 7);
|
||||
macResSizePad = (((macResSize + 127) >> 7) << 7);
|
||||
|
||||
macResOffset = MAC_BINARY_HEADER_SIZE + macDataSizePad;
|
||||
context->file->seek(macResOffset);
|
||||
|
||||
macDataOffset = context->file->readUint32BE() + macResOffset;
|
||||
macMapOffset = context->file->readUint32BE() + macResOffset;
|
||||
macDataLength = context->file->readUint32BE();
|
||||
macMapLength = context->file->readUint32BE();
|
||||
|
||||
if (macDataOffset >= (uint)context->fileSize || macMapOffset >= (uint)context->fileSize ||
|
||||
macDataLength + macMapLength > (uint)context->fileSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
context->file->seek(macMapOffset + 22);
|
||||
|
||||
macResMap.resAttr = context->file->readUint16BE();
|
||||
macResMap.typeOffset = context->file->readUint16BE();
|
||||
macResMap.nameOffset = context->file->readUint16BE();
|
||||
macResMap.numTypes = context->file->readUint16BE();
|
||||
macResMap.numTypes++;
|
||||
|
||||
context->file->seek(macMapOffset + macResMap.typeOffset + 2);
|
||||
|
||||
macResTypes = (MacResType *)calloc(macResMap.numTypes, sizeof(*macResTypes));
|
||||
|
||||
for (i = macResMap.numTypes, macResType = macResTypes; i > 0; i--, macResType++) {
|
||||
macResType->id = context->file->readUint32BE();
|
||||
macResType->items = context->file->readUint16BE();
|
||||
macResType->offset = context->file->readUint16BE();
|
||||
macResType->items++;
|
||||
macResType->resources = (MacResource*)calloc(macResType->items, sizeof(*macResType->resources));
|
||||
}
|
||||
|
||||
for (i = macResMap.numTypes, macResType = macResTypes; i > 0; i--, macResType++) {
|
||||
context->file->seek(macResType->offset + macMapOffset + macResMap.typeOffset);
|
||||
|
||||
for (j = macResType->items, macResource = macResType->resources; j > 0; j--, macResource++) {
|
||||
macResource->id = context->file->readUint16BE();
|
||||
macResource->nameOffset = context->file->readUint16BE();
|
||||
macResource->dataOffset = context->file->readUint32BE();
|
||||
macResSize = context->file->readUint32BE();
|
||||
|
||||
macResource->attr = macResource->dataOffset >> 24;
|
||||
macResource->dataOffset &= 0xFFFFFF;
|
||||
if (macResource->id > macResType->maxItemId) {
|
||||
macResType->maxItemId = macResource->id;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = macResType->items, macResource = macResType->resources; j > 0; j--, macResource++) {
|
||||
if (macResource->nameOffset != -1) {
|
||||
context->file->seek(macResource->nameOffset + macMapOffset + macResMap.nameOffset);
|
||||
macNameLen = context->file->readByte();
|
||||
context->file->read(macResource->name, macNameLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
for (i = macResMap.numTypes, macResType = macResTypes; i > 0; i--, macResType++) {
|
||||
//getting offsets & sizes of midi
|
||||
if (((context->fileType & GAME_MUSICFILE_GM) > 0) && (macResType->id == ID_MIDI)) {
|
||||
|
||||
context->count = macResType->maxItemId + 1;
|
||||
context->table = (ResourceData *)calloc(context->count, sizeof(*context->table));
|
||||
for (j = macResType->items, macResource = macResType->resources; j > 0; j--, macResource++) {
|
||||
context->file->seek(macDataOffset + macResource->dataOffset);
|
||||
context->table[macResource->id].size = context->file->readUint32BE();
|
||||
context->table[macResource->id].offset = context->file->pos();
|
||||
}
|
||||
notSagaContext = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//free
|
||||
for (i = 0; i < macResMap.numTypes; i++) {
|
||||
free(macResTypes[i].resources);
|
||||
}
|
||||
free(macResTypes);
|
||||
|
||||
if ((!notSagaContext) && (!loadResContext(context, MAC_BINARY_HEADER_SIZE, macDataSize))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Saga
|
||||
|
@ -79,7 +79,7 @@ class PalAnim;
|
||||
class Puzzle;
|
||||
class Resource;
|
||||
|
||||
struct ResourceContext;
|
||||
class ResourceContext;
|
||||
struct StringList;
|
||||
|
||||
using Common::MemoryReadStream;
|
||||
|
@ -168,7 +168,7 @@ Scene::Scene(SagaEngine *vm) : _vm(vm) {
|
||||
memoryError("Scene::Scene()");
|
||||
}
|
||||
|
||||
MemoryReadStreamEndian readS(sceneLUTPointer, sceneLUTLength, _sceneContext->isBigEndian);
|
||||
MemoryReadStreamEndian readS(sceneLUTPointer, sceneLUTLength, _sceneContext->isBigEndian());
|
||||
|
||||
for (i = 0; i < _sceneCount; i++) {
|
||||
_sceneLUT[i] = readS.readUint16();
|
||||
@ -929,7 +929,7 @@ void Scene::loadSceneDescriptor(uint32 resourceId) {
|
||||
_vm->_resource->loadResource(_sceneContext, resourceId, sceneDescriptorData, sceneDescriptorDataLength);
|
||||
|
||||
if (sceneDescriptorDataLength == 16) {
|
||||
MemoryReadStreamEndian readS(sceneDescriptorData, sceneDescriptorDataLength, _sceneContext->isBigEndian);
|
||||
MemoryReadStreamEndian readS(sceneDescriptorData, sceneDescriptorDataLength, _sceneContext->isBigEndian());
|
||||
|
||||
_sceneDescription.flags = readS.readSint16();
|
||||
_sceneDescription.resourceListResourceId = readS.readSint16();
|
||||
@ -960,7 +960,7 @@ void Scene::loadSceneResourceList(uint32 resourceId) {
|
||||
_vm->_resource->loadResource(_sceneContext, resourceId, resourceListData, resourceListDataLength);
|
||||
|
||||
if ((resourceListDataLength % SAGA_RESLIST_ENTRY_LEN) == 0) {
|
||||
MemoryReadStreamEndian readS(resourceListData, resourceListDataLength, _sceneContext->isBigEndian);
|
||||
MemoryReadStreamEndian readS(resourceListData, resourceListDataLength, _sceneContext->isBigEndian());
|
||||
|
||||
// Allocate memory for scene resource list
|
||||
_resourceListCount = resourceListDataLength / SAGA_RESLIST_ENTRY_LEN;
|
||||
@ -1302,7 +1302,7 @@ void Scene::loadSceneEntryList(const byte* resourcePointer, size_t resourceLengt
|
||||
|
||||
_entryList.entryListCount = resourceLength / 8;
|
||||
|
||||
MemoryReadStreamEndian readS(resourcePointer, resourceLength, _sceneContext->isBigEndian);
|
||||
MemoryReadStreamEndian readS(resourcePointer, resourceLength, _sceneContext->isBigEndian());
|
||||
|
||||
|
||||
if (_entryList.entryList)
|
||||
|
@ -109,7 +109,7 @@ SAGA1Script::SAGA1Script(SagaEngine *vm) : Script(vm) {
|
||||
}
|
||||
|
||||
// Convert LUT resource to logical LUT
|
||||
MemoryReadStreamEndian scriptS(resourcePointer, resourceLength, resourceContext->isBigEndian);
|
||||
MemoryReadStreamEndian scriptS(resourcePointer, resourceLength, resourceContext->isBigEndian());
|
||||
for (i = 0; i < _modulesCount; i++) {
|
||||
memset(&_modules[i], 0, sizeof(ModuleData));
|
||||
|
||||
@ -1127,7 +1127,7 @@ void Script::loadModuleBase(ModuleData &module, const byte *resourcePointer, siz
|
||||
|
||||
memcpy(module.moduleBase, resourcePointer, resourceLength);
|
||||
|
||||
MemoryReadStreamEndian scriptS(module.moduleBase, module.moduleBaseSize, _scriptContext->isBigEndian);
|
||||
MemoryReadStreamEndian scriptS(module.moduleBase, module.moduleBaseSize, _scriptContext->isBigEndian());
|
||||
|
||||
module.entryPointsCount = scriptS.readUint16();
|
||||
scriptS.readUint16(); //skip
|
||||
@ -1177,7 +1177,7 @@ void Script::loadVoiceLUT(VoiceLUT &voiceLUT, const byte *resourcePointer, size_
|
||||
error("Script::loadVoiceLUT() not enough memory");
|
||||
}
|
||||
|
||||
MemoryReadStreamEndian scriptS(resourcePointer, resourceLength, _scriptContext->isBigEndian);
|
||||
MemoryReadStreamEndian scriptS(resourcePointer, resourceLength, _scriptContext->isBigEndian());
|
||||
|
||||
for (i = 0; i < voiceLUT.voicesCount; i++) {
|
||||
voiceLUT.voices[i] = scriptS.readUint16();
|
||||
|
@ -48,15 +48,14 @@ namespace Saga {
|
||||
#define RID_IHNM_SFX_LUT 265
|
||||
#define RID_IHNMDEMO_SFX_LUT 222
|
||||
|
||||
SndRes::SndRes(SagaEngine *vm) : _vm(vm) {
|
||||
SndRes::SndRes(SagaEngine *vm) : _vm(vm), _sfxContext(NULL), _voiceContext(NULL), _voiceSerial(-1) {
|
||||
|
||||
// Load sound module resource file contexts
|
||||
_sfxContext = _vm->_resource->getContext(GAME_SOUNDFILE);
|
||||
if (_sfxContext == NULL) {
|
||||
error("SndRes::SndRes resource context not found");
|
||||
}
|
||||
|
||||
_voiceSerial = -1;
|
||||
|
||||
setVoiceBank(0);
|
||||
|
||||
if (_vm->getGameId() == GID_ITE) {
|
||||
@ -117,6 +116,7 @@ SndRes::~SndRes() {
|
||||
}
|
||||
|
||||
void SndRes::setVoiceBank(int serial) {
|
||||
Common::File *file;
|
||||
if (_voiceSerial == serial)
|
||||
return;
|
||||
|
||||
@ -126,12 +126,7 @@ void SndRes::setVoiceBank(int serial) {
|
||||
if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
|
||||
_voiceSerial = serial;
|
||||
// Set a dummy voice context
|
||||
_voiceContext = new ResourceContext();
|
||||
_voiceContext->fileType = GAME_VOICEFILE;
|
||||
_voiceContext->count = 0;
|
||||
_voiceContext->serial = 0;
|
||||
_voiceContext->isBigEndian = true;
|
||||
_voiceContext->isCompressed = false;
|
||||
_voiceContext = new VoiceResourceContext_RES();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -141,16 +136,16 @@ void SndRes::setVoiceBank(int serial) {
|
||||
return;
|
||||
|
||||
// Close previous voice bank file
|
||||
if (_voiceSerial >= 0 && _voiceContext->file->isOpen())
|
||||
_voiceContext->file->close();
|
||||
if (_voiceContext != NULL) {
|
||||
file = _voiceContext->getFile(NULL);
|
||||
if (file->isOpen()) {
|
||||
file->close();
|
||||
}
|
||||
}
|
||||
|
||||
_voiceSerial = serial;
|
||||
|
||||
_voiceContext = _vm->_resource->getContext(GAME_VOICEFILE, _voiceSerial);
|
||||
|
||||
// Open new voice bank file
|
||||
if (!_voiceContext->file->isOpen())
|
||||
_voiceContext->file->open(_voiceContext->fileName);
|
||||
}
|
||||
|
||||
void SndRes::playSound(uint32 resourceId, int volume, bool loop) {
|
||||
@ -199,11 +194,12 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IHNM
|
||||
//TODO: move to resource_res so we can use normal "getResourceData" and "getFile" methods
|
||||
if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
|
||||
char soundFileName[40];
|
||||
int dirIndex = resourceId / 64;
|
||||
|
||||
if ((context->fileType & GAME_VOICEFILE) != 0) {
|
||||
if ((context->fileType() & GAME_VOICEFILE) != 0) {
|
||||
if (_voiceSerial == 0) {
|
||||
sprintf(soundFileName, "Voices/VoicesS/Voices%d/VoicesS%03x", dirIndex, resourceId);
|
||||
} else {
|
||||
@ -217,7 +213,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
|
||||
|
||||
file->open(soundFileName);
|
||||
soundResourceLength = file->size();
|
||||
context->isBigEndian = true;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@ -249,14 +244,14 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
|
||||
bool uncompressedSound = false;
|
||||
// If patch data exists for sound resource 4 (used in ITE intro), don't treat this sound as compressed
|
||||
// Patch data for this resource is in file p2_a.iaf or p2_a.voc
|
||||
if (_vm->getGameId() == GID_ITE && resourceId == 4 && context->table[resourceId].patchData != NULL)
|
||||
if (_vm->getGameId() == GID_ITE && resourceId == 4 && context->getResourceData(resourceId)->patchData != NULL)
|
||||
uncompressedSound = true;
|
||||
|
||||
// FIXME: Currently, the SFX.RES file in IHNM cannot be compressed
|
||||
if (_vm->getGameId() == GID_IHNM && (context->fileType & GAME_SOUNDFILE))
|
||||
if (_vm->getGameId() == GID_IHNM && (context->fileType() & GAME_SOUNDFILE))
|
||||
uncompressedSound = true;
|
||||
|
||||
if (context->isCompressed && !uncompressedSound) {
|
||||
if (context->isCompressed() && !uncompressedSound) {
|
||||
if (header[0] == char(0)) {
|
||||
resourceType = kSoundMP3;
|
||||
} else if (header[0] == char(1)) {
|
||||
@ -269,7 +264,7 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
|
||||
}
|
||||
|
||||
// Default sound type is 16-bit signed PCM, used in ITE by PCM and VOX files
|
||||
buffer.isCompressed = context->isCompressed;
|
||||
buffer.isCompressed = context->isCompressed();
|
||||
buffer.soundType = resourceType;
|
||||
buffer.originalSize = 0;
|
||||
// Set default flags and frequency for PCM, VOC and VOX files, which got no header
|
||||
@ -281,20 +276,20 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
|
||||
buffer.flags &= ~Audio::Mixer::FLAG_16BITS;
|
||||
} else {
|
||||
// Voice files in newer ITE demo versions are OKI ADPCM (VOX) encoded
|
||||
if (!scumm_stricmp(context->fileName, "voicesd.rsc"))
|
||||
if (!scumm_stricmp(context->fileName(), "voicesd.rsc"))
|
||||
resourceType = kSoundVOX;
|
||||
}
|
||||
}
|
||||
buffer.buffer = NULL;
|
||||
|
||||
// Check for LE sounds
|
||||
if (!context->isBigEndian)
|
||||
if (!context->isBigEndian())
|
||||
buffer.flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
|
||||
if ((context->fileType & GAME_VOICEFILE) && (_vm->getFeatures() & GF_LE_VOICES))
|
||||
if ((context->fileType() & GAME_VOICEFILE) && (_vm->getFeatures() & GF_LE_VOICES))
|
||||
buffer.flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
|
||||
|
||||
// Older Mac versions of ITE were Macbinary packed
|
||||
int soundOffset = (context->fileType & GAME_MACBINARY) ? 36 : 0;
|
||||
int soundOffset = (context->fileType() & GAME_MACBINARY) ? 36 : 0;
|
||||
|
||||
switch (resourceType) {
|
||||
case kSoundPCM:
|
||||
@ -404,7 +399,7 @@ int SndRes::getVoiceLength(uint32 resourceId) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!_voiceContext->isCompressed || buffer.originalSize == 0)
|
||||
if (!_voiceContext->isCompressed() || buffer.originalSize == 0)
|
||||
msDouble = (double)buffer.size;
|
||||
else
|
||||
msDouble = (double)buffer.originalSize;
|
||||
|
@ -106,7 +106,7 @@ void Sprite::loadList(int resourceId, SpriteList &spriteList) {
|
||||
return;
|
||||
}
|
||||
|
||||
MemoryReadStreamEndian readS(spriteListData, spriteListLength, _spriteContext->isBigEndian);
|
||||
MemoryReadStreamEndian readS(spriteListData, spriteListLength, _spriteContext->isBigEndian());
|
||||
|
||||
spriteCount = readS.readUint16();
|
||||
|
||||
@ -142,7 +142,7 @@ void Sprite::loadList(int resourceId, SpriteList &spriteList) {
|
||||
spritePointer += offset;
|
||||
|
||||
if (bigHeader) {
|
||||
MemoryReadStreamEndian readS2(spritePointer, 8, _spriteContext->isBigEndian);
|
||||
MemoryReadStreamEndian readS2(spritePointer, 8, _spriteContext->isBigEndian());
|
||||
|
||||
spriteInfo->xAlign = readS2.readSint16();
|
||||
spriteInfo->yAlign = readS2.readSint16();
|
||||
|
Loading…
Reference in New Issue
Block a user