Initial commit
This commit is contained in:
449
engines/scumm/he/resource_he.cpp
Normal file
449
engines/scumm/he/resource_he.cpp
Normal file
@@ -0,0 +1,449 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/scumm.h"
|
||||
#include "scumm/file.h"
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/resource.h"
|
||||
#include "scumm/he/resource_he.h"
|
||||
#include "scumm/he/sound_he.h"
|
||||
#include "scumm/util.h"
|
||||
|
||||
#include "audio/decoders/wave.h"
|
||||
#include "graphics/cursorman.h"
|
||||
#include "graphics/maccursor.h"
|
||||
#include "graphics/wincursor.h"
|
||||
|
||||
#include "common/archive.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/system.h"
|
||||
#include "common/formats/winexe_pe.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
ResExtractor::ResExtractor(ScummEngine_v70he *scumm)
|
||||
: _vm(scumm) {
|
||||
|
||||
memset(_cursorCache, 0, sizeof(_cursorCache));
|
||||
}
|
||||
|
||||
ResExtractor::~ResExtractor() {
|
||||
for (int i = 0; i < MAX_CACHED_CURSORS; ++i) {
|
||||
CachedCursor *cc = &_cursorCache[i];
|
||||
if (cc->valid) {
|
||||
delete[] cc->bitmap;
|
||||
delete[] cc->palette;
|
||||
}
|
||||
}
|
||||
|
||||
memset(_cursorCache, 0, sizeof(_cursorCache));
|
||||
}
|
||||
|
||||
ResExtractor::CachedCursor *ResExtractor::findCachedCursor(int id) {
|
||||
for (int i = 0; i < MAX_CACHED_CURSORS; ++i)
|
||||
if (_cursorCache[i].valid && _cursorCache[i].id == id)
|
||||
return &_cursorCache[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ResExtractor::CachedCursor *ResExtractor::getCachedCursorSlot() {
|
||||
uint32 minLastUsed = 0;
|
||||
CachedCursor *r = nullptr;
|
||||
|
||||
for (int i = 0; i < MAX_CACHED_CURSORS; ++i) {
|
||||
CachedCursor *cc = &_cursorCache[i];
|
||||
if (!cc->valid)
|
||||
return cc;
|
||||
|
||||
if (minLastUsed == 0 || cc->lastUsed < minLastUsed) {
|
||||
minLastUsed = cc->lastUsed;
|
||||
r = cc;
|
||||
}
|
||||
}
|
||||
|
||||
assert(r);
|
||||
delete[] r->bitmap;
|
||||
delete[] r->palette;
|
||||
memset(r, 0, sizeof(CachedCursor));
|
||||
return r;
|
||||
}
|
||||
|
||||
void ResExtractor::setCursor(int id) {
|
||||
CachedCursor *cc = findCachedCursor(id);
|
||||
|
||||
if (cc != nullptr) {
|
||||
debug(7, "Found cursor %d in cache slot %lu", id, (long)(cc - _cursorCache));
|
||||
} else {
|
||||
cc = getCachedCursorSlot();
|
||||
assert(cc && !cc->valid);
|
||||
|
||||
if (!extractResource(id, cc))
|
||||
error("Could not extract cursor %d", id);
|
||||
|
||||
debug(7, "Adding cursor %d to cache slot %lu", id, (long)(cc - _cursorCache));
|
||||
|
||||
cc->valid = true;
|
||||
cc->id = id;
|
||||
cc->lastUsed = g_system->getMillis();
|
||||
}
|
||||
|
||||
if (cc->palette)
|
||||
CursorMan.replaceCursorPalette(cc->palette, 0, cc->palSize);
|
||||
|
||||
_vm->setCursorHotspot(cc->hotspotX, cc->hotspotY);
|
||||
_vm->setCursorFromBuffer(cc->bitmap, cc->width, cc->height, cc->width);
|
||||
}
|
||||
|
||||
|
||||
Win32ResExtractor::Win32ResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) {
|
||||
_exe = new Common::PEResources();
|
||||
}
|
||||
|
||||
Win32ResExtractor::~Win32ResExtractor() {
|
||||
delete _exe;
|
||||
}
|
||||
|
||||
bool Win32ResExtractor::extractResource(int id, CachedCursor *cc) {
|
||||
if (_fileName.empty()) { // We are running for the first time
|
||||
_fileName = _vm->generateFilename(-3);
|
||||
|
||||
if (!_exe->loadFromEXE(_fileName))
|
||||
error("Cannot open file %s", _fileName.toString(Common::Path::kNativeSeparator).c_str());
|
||||
}
|
||||
|
||||
Graphics::WinCursorGroup *group = Graphics::WinCursorGroup::createCursorGroup(_exe, id);
|
||||
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
Graphics::Cursor *cursor = group->cursors[0].cursor;
|
||||
|
||||
cc->bitmap = new byte[cursor->getWidth() * cursor->getHeight()];
|
||||
cc->width = cursor->getWidth();
|
||||
cc->height = cursor->getHeight();
|
||||
cc->hotspotX = cursor->getHotspotX();
|
||||
cc->hotspotY = cursor->getHotspotY();
|
||||
|
||||
// Convert from the paletted format to the SCUMM palette
|
||||
const byte *srcBitmap = cursor->getSurface();
|
||||
const byte *srcMask = cursor->getMask();
|
||||
|
||||
for (int i = 0; i < cursor->getWidth() * cursor->getHeight(); i++) {
|
||||
const bool isTransparent = (srcMask ? (srcMask[i] != kCursorMaskOpaque) : (srcBitmap[i] == cursor->getKeyColor()));
|
||||
|
||||
if (isTransparent)
|
||||
cc->bitmap[i] = 255;
|
||||
else if (srcBitmap[i] == 0) // Black
|
||||
cc->bitmap[i] = 253;
|
||||
else // White
|
||||
cc->bitmap[i] = 254;
|
||||
}
|
||||
|
||||
delete group;
|
||||
return true;
|
||||
}
|
||||
|
||||
MacResExtractor::MacResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) {
|
||||
_resMgr = nullptr;
|
||||
}
|
||||
|
||||
bool MacResExtractor::extractResource(int id, CachedCursor *cc) {
|
||||
// Create the MacResManager if not created already
|
||||
if (_resMgr == nullptr) {
|
||||
_resMgr = new Common::MacResManager();
|
||||
_fileName = _vm->generateFilename(-3);
|
||||
if (!_resMgr->open(_fileName))
|
||||
error("Cannot open file %s", _fileName.toString(Common::Path::kNativeSeparator).c_str());
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *dataStream = _resMgr->getResource(MKTAG('c','r','s','r'), id + 1000);
|
||||
|
||||
if (!dataStream)
|
||||
return false;
|
||||
|
||||
// If we don't have a cursor palette, force monochrome cursors
|
||||
bool forceMonochrome = !_vm->_system->hasFeature(OSystem::kFeatureCursorPalette);
|
||||
|
||||
Graphics::MacCursor *macCursor = new Graphics::MacCursor();
|
||||
|
||||
if (!macCursor->readFromStream(*dataStream, forceMonochrome)) {
|
||||
delete dataStream;
|
||||
delete macCursor;
|
||||
return false;
|
||||
}
|
||||
|
||||
cc->bitmap = new byte[macCursor->getWidth() * macCursor->getHeight()];
|
||||
cc->width = macCursor->getWidth();
|
||||
cc->height = macCursor->getHeight();
|
||||
cc->hotspotX = macCursor->getHotspotX();
|
||||
cc->hotspotY = macCursor->getHotspotY();
|
||||
|
||||
if (forceMonochrome) {
|
||||
// Convert to the SCUMM palette
|
||||
const byte *srcBitmap = macCursor->getSurface();
|
||||
|
||||
for (int i = 0; i < macCursor->getWidth() * macCursor->getHeight(); i++) {
|
||||
if (srcBitmap[i] == macCursor->getKeyColor()) // Transparent
|
||||
cc->bitmap[i] = 255;
|
||||
else if (srcBitmap[i] == 0) // Black
|
||||
cc->bitmap[i] = 253;
|
||||
else // White
|
||||
cc->bitmap[i] = 254;
|
||||
}
|
||||
} else {
|
||||
// Copy data and palette
|
||||
|
||||
// Sanity check. This code assumes that the key color is the same
|
||||
assert(macCursor->getKeyColor() == 255);
|
||||
|
||||
memcpy(cc->bitmap, macCursor->getSurface(), macCursor->getWidth() * macCursor->getHeight());
|
||||
|
||||
cc->palette = new byte[256 * 3];
|
||||
cc->palSize = 256;
|
||||
memcpy(cc->palette, macCursor->getPalette(), 256 * 3);
|
||||
}
|
||||
|
||||
delete macCursor;
|
||||
delete dataStream;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScummEngine_v70he::readRoomsOffsets() {
|
||||
int num, i;
|
||||
byte *ptr;
|
||||
|
||||
debug(9, "readRoomOffsets()");
|
||||
|
||||
num = READ_LE_UINT16(_heV7RoomOffsets);
|
||||
ptr = _heV7RoomOffsets + 2;
|
||||
for (i = 0; i < num; i++) {
|
||||
_res->_types[rtRoom][i]._roomoffs = READ_LE_UINT32(ptr);
|
||||
ptr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void ScummEngine_v70he::readGlobalObjects() {
|
||||
int num = _fileHandle->readUint16LE();
|
||||
assert(num == _numGlobalObjects);
|
||||
assert(_objectStateTable);
|
||||
assert(_objectOwnerTable);
|
||||
|
||||
_fileHandle->read(_objectStateTable, num);
|
||||
_fileHandle->read(_objectOwnerTable, num);
|
||||
_fileHandle->read(_objectRoomTable, num);
|
||||
|
||||
_fileHandle->read(_classData, num * sizeof(uint32));
|
||||
|
||||
#if defined(SCUMM_BIG_ENDIAN)
|
||||
// Correct the endianess if necessary
|
||||
for (int i = 0; i != num; i++)
|
||||
_classData[i] = FROM_LE_32(_classData[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
void ScummEngine_v99he::readMAXS(int blockSize) {
|
||||
if (blockSize == 52) {
|
||||
_numVariables = _fileHandle->readUint16LE();
|
||||
_fileHandle->readUint16LE();
|
||||
_numRoomVariables = _fileHandle->readUint16LE();
|
||||
_numLocalObjects = _fileHandle->readUint16LE();
|
||||
_numArray = _fileHandle->readUint16LE();
|
||||
_fileHandle->readUint16LE();
|
||||
_fileHandle->readUint16LE();
|
||||
_numFlObject = _fileHandle->readUint16LE();
|
||||
_numInventory = _fileHandle->readUint16LE();
|
||||
_numRooms = _fileHandle->readUint16LE();
|
||||
_numScripts = _fileHandle->readUint16LE();
|
||||
_numSounds = _fileHandle->readUint16LE();
|
||||
_numCharsets = _fileHandle->readUint16LE();
|
||||
_numCostumes = _fileHandle->readUint16LE();
|
||||
_numGlobalObjects = _fileHandle->readUint16LE();
|
||||
_numImages = _fileHandle->readUint16LE();
|
||||
_numSprites = _fileHandle->readUint16LE();
|
||||
_numLocalScripts = _fileHandle->readUint16LE();
|
||||
_HEHeapSize = _fileHandle->readUint16LE();
|
||||
_numPalettes = _fileHandle->readUint16LE();
|
||||
_numWindows = _fileHandle->readUint16LE();
|
||||
_numTalkies = _fileHandle->readUint16LE();
|
||||
_numNewNames = 10;
|
||||
|
||||
_objectRoomTable = (byte *)reallocateArray(_objectRoomTable, _numGlobalObjects, 1);
|
||||
_numGlobalScripts = 2048;
|
||||
} else
|
||||
ScummEngine_v90he::readMAXS(blockSize);
|
||||
}
|
||||
|
||||
void ScummEngine_v90he::readMAXS(int blockSize) {
|
||||
if (blockSize == 46) {
|
||||
_numVariables = _fileHandle->readUint16LE();
|
||||
_fileHandle->readUint16LE();
|
||||
_numRoomVariables = _fileHandle->readUint16LE();
|
||||
_numLocalObjects = _fileHandle->readUint16LE();
|
||||
_numArray = _fileHandle->readUint16LE();
|
||||
_fileHandle->readUint16LE();
|
||||
_fileHandle->readUint16LE();
|
||||
_numFlObject = _fileHandle->readUint16LE();
|
||||
_numInventory = _fileHandle->readUint16LE();
|
||||
_numRooms = _fileHandle->readUint16LE();
|
||||
_numScripts = _fileHandle->readUint16LE();
|
||||
_numSounds = _fileHandle->readUint16LE();
|
||||
_numCharsets = _fileHandle->readUint16LE();
|
||||
_numCostumes = _fileHandle->readUint16LE();
|
||||
_numGlobalObjects = _fileHandle->readUint16LE();
|
||||
_numImages = _fileHandle->readUint16LE();
|
||||
_numSprites = _fileHandle->readUint16LE();
|
||||
_numLocalScripts = _fileHandle->readUint16LE();
|
||||
_HEHeapSize = _fileHandle->readUint16LE();
|
||||
|
||||
// In the original, this is hardcoded as well...
|
||||
if (_game.heversion > 90)
|
||||
_numPalettes = 16;
|
||||
|
||||
_numNewNames = 10;
|
||||
|
||||
_objectRoomTable = (byte *)reallocateArray(_objectRoomTable, _numGlobalObjects, 1);
|
||||
if (_game.features & GF_HE_985)
|
||||
_numGlobalScripts = 2048;
|
||||
else
|
||||
_numGlobalScripts = 200;
|
||||
} else
|
||||
ScummEngine_v72he::readMAXS(blockSize);
|
||||
}
|
||||
|
||||
void ScummEngine_v72he::readMAXS(int blockSize) {
|
||||
if (blockSize == 40) {
|
||||
_numVariables = _fileHandle->readUint16LE();
|
||||
_fileHandle->readUint16LE();
|
||||
_numBitVariables = _numRoomVariables = _fileHandle->readUint16LE();
|
||||
_numLocalObjects = _fileHandle->readUint16LE();
|
||||
_numArray = _fileHandle->readUint16LE();
|
||||
_fileHandle->readUint16LE();
|
||||
_numVerbs = _fileHandle->readUint16LE();
|
||||
_numFlObject = _fileHandle->readUint16LE();
|
||||
_numInventory = _fileHandle->readUint16LE();
|
||||
_numRooms = _fileHandle->readUint16LE();
|
||||
_numScripts = _fileHandle->readUint16LE();
|
||||
_numSounds = _fileHandle->readUint16LE();
|
||||
_numCharsets = _fileHandle->readUint16LE();
|
||||
_numCostumes = _fileHandle->readUint16LE();
|
||||
_numGlobalObjects = _fileHandle->readUint16LE();
|
||||
_numImages = _fileHandle->readUint16LE();
|
||||
_numNewNames = 10;
|
||||
|
||||
_objectRoomTable = (byte *)reallocateArray(_objectRoomTable, _numGlobalObjects, 1);
|
||||
_numGlobalScripts = 200;
|
||||
} else
|
||||
ScummEngine_v6::readMAXS(blockSize);
|
||||
}
|
||||
|
||||
byte *ScummEngine_v72he::getStringAddress(ResId idx) {
|
||||
byte *addr = getResourceAddress(rtString, idx);
|
||||
if (addr == NULL)
|
||||
return NULL;
|
||||
return ((ScummEngine_v72he::ArrayHeader *)addr)->data;
|
||||
}
|
||||
|
||||
int ScummEngine_v72he::getSoundResourceSize(ResId id) {
|
||||
const byte *ptr;
|
||||
int offs;
|
||||
int size = 0;
|
||||
|
||||
if (id >= _numSounds) {
|
||||
if (!((SoundHE *)_sound)->getHEMusicDetails(id, offs, size)) {
|
||||
debug(0, "getSoundResourceSize: musicID %d not found", id);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
ptr = getResourceAddress(rtSound, id);
|
||||
if (!ptr)
|
||||
return 0;
|
||||
|
||||
if (_game.heversion < 95) {
|
||||
if (_game.version >= 80) {
|
||||
ptr = findResourceData(MKTAG('S', 'D', 'A', 'T'), ptr);
|
||||
if (!ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return READ_BE_UINT32(ptr + 4) - 8;
|
||||
} else {
|
||||
return READ_BE_UINT32(ptr + HSND_RES_OFFSET_LEN3) - 8;
|
||||
}
|
||||
} else {
|
||||
if (READ_BE_UINT32(ptr) == MKTAG('W', 'S', 'O', 'U')) {
|
||||
// Wrapped .wav file
|
||||
const byte *data = ((SoundHE *)_sound)->findWavBlock(MKTAG('d', 'a', 't', 'a'), ptr);
|
||||
if (data)
|
||||
return READ_LE_UINT32(data + 4);
|
||||
} else {
|
||||
ptr = findResourceData(MKTAG('S', 'D', 'A', 'T'), ptr);
|
||||
if (!ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return READ_BE_UINT32(ptr + 4) - 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void ScummEngine_v90he::setResourceOffHeap(int typeId, int resId, int val) {
|
||||
debug(0, "setResourceOffHeap: type %d resId %d toggle %d", typeId, resId, val);
|
||||
ResType type;
|
||||
|
||||
switch (typeId) {
|
||||
case 1:
|
||||
type = rtRoom;
|
||||
break;
|
||||
case 2:
|
||||
type = rtScript;
|
||||
break;
|
||||
case 3:
|
||||
type = rtCostume;
|
||||
break;
|
||||
case 4:
|
||||
type = rtSound;
|
||||
break;
|
||||
case 6:
|
||||
type = rtCharset;
|
||||
break;
|
||||
case 19:
|
||||
type = rtImage;
|
||||
break;
|
||||
default:
|
||||
error("setResourceOffHeap: default case %d", typeId);
|
||||
}
|
||||
|
||||
if (val == 1) {
|
||||
_res->setOffHeap(type, resId);
|
||||
} else {
|
||||
_res->setOnHeap(type, resId);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // End of namespace Scumm
|
||||
Reference in New Issue
Block a user