mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-12 12:09:15 +00:00
GOB: Add support for different methods of handling Endianness
The Once Upon A Time games handle endianness different in ANI, DEC and RXY files than Geisha does. We need to support both approaches.
This commit is contained in:
parent
83896dea3e
commit
4fc3a88c5f
@ -37,30 +37,38 @@ ANIFile::ANIFile(GobEngine *vm, const Common::String &fileName,
|
||||
uint16 width, uint8 bpp) : _vm(vm),
|
||||
_width(width), _bpp(bpp), _hasPadding(false) {
|
||||
|
||||
Common::SeekableReadStream *ani = _vm->_dataIO->getFile(fileName);
|
||||
bool bigEndian = false;
|
||||
Common::String endianFileName = fileName;
|
||||
|
||||
if ((_vm->getEndiannessMethod() == kEndiannessMethodAltFile) &&
|
||||
!_vm->_dataIO->hasFile(fileName)) {
|
||||
// If the game has alternate big-endian files, look if one exist
|
||||
|
||||
Common::String alternateFileName = fileName;
|
||||
alternateFileName.setChar('_', 0);
|
||||
|
||||
if (_vm->_dataIO->hasFile(alternateFileName)) {
|
||||
bigEndian = true;
|
||||
endianFileName = alternateFileName;
|
||||
}
|
||||
} else if ((_vm->getEndiannessMethod() == kEndiannessMethodBE) ||
|
||||
((_vm->getEndiannessMethod() == kEndiannessMethodSystem) &&
|
||||
(_vm->getEndianness() == kEndiannessBE)))
|
||||
// Game always little endian or it follows the system and it is big endian
|
||||
bigEndian = true;
|
||||
|
||||
Common::SeekableReadStream *ani = _vm->_dataIO->getFile(endianFileName);
|
||||
if (ani) {
|
||||
Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), false, DisposeAfterUse::YES);
|
||||
|
||||
load(sub, fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
// File doesn't exist, try to open the big-endian'd alternate file
|
||||
Common::String alternateFileName = fileName;
|
||||
alternateFileName.setChar('_', 0);
|
||||
|
||||
ani = _vm->_dataIO->getFile(alternateFileName);
|
||||
if (ani) {
|
||||
Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), true, DisposeAfterUse::YES);
|
||||
Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), bigEndian, DisposeAfterUse::YES);
|
||||
|
||||
// The big endian version pads a few fields to even size
|
||||
_hasPadding = true;
|
||||
_hasPadding = bigEndian;
|
||||
|
||||
load(sub, fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
warning("ANIFile::ANIFile(): No such file \"%s\"", fileName.c_str());
|
||||
warning("ANIFile::ANIFile(): No such file \"%s\" (\"%s\")", endianFileName.c_str(), fileName.c_str());
|
||||
}
|
||||
|
||||
ANIFile::~ANIFile() {
|
||||
|
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/substream.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "gob/gob.h"
|
||||
@ -143,7 +144,13 @@ void CMPFile::loadCMP(Common::SeekableReadStream &cmp) {
|
||||
}
|
||||
|
||||
void CMPFile::loadRXY(Common::SeekableReadStream &rxy) {
|
||||
_coordinates = new RXYFile(rxy);
|
||||
bool bigEndian = (_vm->getEndiannessMethod() == kEndiannessMethodBE) ||
|
||||
((_vm->getEndiannessMethod() == kEndiannessMethodSystem) &&
|
||||
(_vm->getEndianness() == kEndiannessBE));
|
||||
|
||||
Common::SeekableSubReadStreamEndian sub(&rxy, 0, rxy.size(), bigEndian, DisposeAfterUse::NO);
|
||||
|
||||
_coordinates = new RXYFile(sub);
|
||||
|
||||
for (uint i = 0; i < _coordinates->size(); i++) {
|
||||
const RXYFile::Coordinates &c = (*_coordinates)[i];
|
||||
|
@ -38,30 +38,38 @@ DECFile::DECFile(GobEngine *vm, const Common::String &fileName,
|
||||
uint16 width, uint16 height, uint8 bpp) : _vm(vm),
|
||||
_width(width), _height(height), _bpp(bpp), _hasPadding(false), _backdrop(0) {
|
||||
|
||||
Common::SeekableReadStream *dec = _vm->_dataIO->getFile(fileName);
|
||||
if (dec) {
|
||||
Common::SeekableSubReadStreamEndian sub(dec, 0, dec->size(), false, DisposeAfterUse::YES);
|
||||
bool bigEndian = false;
|
||||
Common::String endianFileName = fileName;
|
||||
|
||||
load(sub, fileName);
|
||||
return;
|
||||
}
|
||||
if ((_vm->getEndiannessMethod() == kEndiannessMethodAltFile) &&
|
||||
!_vm->_dataIO->hasFile(fileName)) {
|
||||
// If the game has alternate big-endian files, look if one exist
|
||||
|
||||
// File doesn't exist, try to open the big-endian'd alternate file
|
||||
Common::String alternateFileName = fileName;
|
||||
alternateFileName.setChar('_', 0);
|
||||
Common::String alternateFileName = fileName;
|
||||
alternateFileName.setChar('_', 0);
|
||||
|
||||
dec = _vm->_dataIO->getFile(alternateFileName);
|
||||
if (dec) {
|
||||
Common::SeekableSubReadStreamEndian sub(dec, 0, dec->size(), true, DisposeAfterUse::YES);
|
||||
if (_vm->_dataIO->hasFile(alternateFileName)) {
|
||||
bigEndian = true;
|
||||
endianFileName = alternateFileName;
|
||||
}
|
||||
} else if ((_vm->getEndiannessMethod() == kEndiannessMethodBE) ||
|
||||
((_vm->getEndiannessMethod() == kEndiannessMethodSystem) &&
|
||||
(_vm->getEndianness() == kEndiannessBE)))
|
||||
// Game always little endian or it follows the system and it is big endian
|
||||
bigEndian = true;
|
||||
|
||||
Common::SeekableReadStream *ani = _vm->_dataIO->getFile(endianFileName);
|
||||
if (ani) {
|
||||
Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), bigEndian, DisposeAfterUse::YES);
|
||||
|
||||
// The big endian version pads a few fields to even size
|
||||
_hasPadding = true;
|
||||
_hasPadding = bigEndian;
|
||||
|
||||
load(sub, fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
warning("DECFile::DECFile(): No such file \"%s\"", fileName.c_str());
|
||||
warning("DECFile::DECFile(): No such file \"%s\" (\"%s\")", endianFileName.c_str(), fileName.c_str());
|
||||
}
|
||||
|
||||
DECFile::~DECFile() {
|
||||
|
@ -184,6 +184,10 @@ void GobEngine::validateVideoMode(int16 videoMode) {
|
||||
error("Video mode 0x%X is not supported", videoMode);
|
||||
}
|
||||
|
||||
EndiannessMethod GobEngine::getEndiannessMethod() const {
|
||||
return _endiannessMethod;
|
||||
}
|
||||
|
||||
Endianness GobEngine::getEndianness() const {
|
||||
if ((getPlatform() == Common::kPlatformAmiga) ||
|
||||
(getPlatform() == Common::kPlatformMacintosh) ||
|
||||
@ -403,6 +407,8 @@ Common::Error GobEngine::initGameParts() {
|
||||
// just detect some devices some of which will be always there if the music is not disabled
|
||||
_noMusic = MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK | MDT_MIDI | MDT_ADLIB)) == MT_NULL ? true : false;
|
||||
|
||||
_endiannessMethod = kEndiannessMethodSystem;
|
||||
|
||||
_global = new Global(this);
|
||||
_util = new Util(this);
|
||||
_dataIO = new DataIO();
|
||||
@ -433,6 +439,8 @@ Common::Error GobEngine::initGameParts() {
|
||||
_goblin = new Goblin_v1(this);
|
||||
_scenery = new Scenery_v1(this);
|
||||
_saveLoad = new SaveLoad_Geisha(this, _targetName.c_str());
|
||||
|
||||
_endiannessMethod = kEndiannessMethodAltFile;
|
||||
break;
|
||||
|
||||
case kGameTypeFascination:
|
||||
|
@ -149,6 +149,13 @@ enum Features {
|
||||
kFeaturesTrueColor = 1 << 7
|
||||
};
|
||||
|
||||
enum EndiannessMethod {
|
||||
kEndiannessMethodLE, ///< Always little endian.
|
||||
kEndiannessMethodBE, ///< Always big endian.
|
||||
kEndiannessMethodSystem, ///< Follows system endianness.
|
||||
kEndiannessMethodAltFile ///< Different endianness in alternate file.
|
||||
};
|
||||
|
||||
enum {
|
||||
kDebugFuncOp = 1 << 0,
|
||||
kDebugDrawOp = 1 << 1,
|
||||
@ -172,6 +179,8 @@ private:
|
||||
int32 _features;
|
||||
Common::Platform _platform;
|
||||
|
||||
EndiannessMethod _endiannessMethod;
|
||||
|
||||
uint32 _pauseStart;
|
||||
|
||||
// Engine APIs
|
||||
@ -232,6 +241,7 @@ public:
|
||||
|
||||
void pauseGame();
|
||||
|
||||
EndiannessMethod getEndiannessMethod() const;
|
||||
Endianness getEndianness() const;
|
||||
Common::Platform getPlatform() const;
|
||||
GameType getGameType() const;
|
||||
|
@ -21,12 +21,19 @@
|
||||
*/
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/substream.h"
|
||||
|
||||
#include "gob/rxyfile.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
RXYFile::RXYFile(Common::SeekableReadStream &rxy) : _width(0), _height(0) {
|
||||
Common::SeekableSubReadStreamEndian sub(&rxy, 0, rxy.size(), false, DisposeAfterUse::NO);
|
||||
|
||||
load(sub);
|
||||
}
|
||||
|
||||
RXYFile::RXYFile(Common::SeekableSubReadStreamEndian &rxy) : _width(0), _height(0) {
|
||||
load(rxy);
|
||||
}
|
||||
|
||||
@ -64,22 +71,22 @@ const RXYFile::Coordinates &RXYFile::operator[](uint i) const {
|
||||
return _coords[i];
|
||||
}
|
||||
|
||||
void RXYFile::load(Common::SeekableReadStream &rxy) {
|
||||
void RXYFile::load(Common::SeekableSubReadStreamEndian &rxy) {
|
||||
if (rxy.size() < 2)
|
||||
return;
|
||||
|
||||
rxy.seek(0);
|
||||
|
||||
_realCount = rxy.readUint16LE();
|
||||
_realCount = rxy.readUint16();
|
||||
|
||||
uint16 count = (rxy.size() - 2) / 8;
|
||||
|
||||
_coords.resize(count);
|
||||
for (CoordArray::iterator c = _coords.begin(); c != _coords.end(); ++c) {
|
||||
c->left = rxy.readUint16LE();
|
||||
c->right = rxy.readUint16LE();
|
||||
c->top = rxy.readUint16LE();
|
||||
c->bottom = rxy.readUint16LE();
|
||||
c->left = rxy.readUint16();
|
||||
c->right = rxy.readUint16();
|
||||
c->top = rxy.readUint16();
|
||||
c->bottom = rxy.readUint16();
|
||||
|
||||
if (c->left != 0xFFFF) {
|
||||
_width = MAX<uint16>(_width , c->right + 1);
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
class SeekableSubReadStreamEndian;
|
||||
}
|
||||
|
||||
namespace Gob {
|
||||
@ -46,6 +47,7 @@ public:
|
||||
};
|
||||
|
||||
RXYFile(Common::SeekableReadStream &rxy);
|
||||
RXYFile(Common::SeekableSubReadStreamEndian &rxy);
|
||||
RXYFile(uint16 width, uint16 height);
|
||||
~RXYFile();
|
||||
|
||||
@ -71,7 +73,7 @@ private:
|
||||
uint16 _height;
|
||||
|
||||
|
||||
void load(Common::SeekableReadStream &rxy);
|
||||
void load(Common::SeekableSubReadStreamEndian &rxy);
|
||||
};
|
||||
|
||||
} // End of namespace Gob
|
||||
|
Loading…
Reference in New Issue
Block a user