mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-04 09:18:38 +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),
|
uint16 width, uint8 bpp) : _vm(vm),
|
||||||
_width(width), _bpp(bpp), _hasPadding(false) {
|
_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) {
|
if (ani) {
|
||||||
Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), false, DisposeAfterUse::YES);
|
Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), bigEndian, 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);
|
|
||||||
|
|
||||||
// The big endian version pads a few fields to even size
|
// The big endian version pads a few fields to even size
|
||||||
_hasPadding = true;
|
_hasPadding = bigEndian;
|
||||||
|
|
||||||
load(sub, fileName);
|
load(sub, fileName);
|
||||||
return;
|
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() {
|
ANIFile::~ANIFile() {
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common/stream.h"
|
#include "common/stream.h"
|
||||||
|
#include "common/substream.h"
|
||||||
#include "common/str.h"
|
#include "common/str.h"
|
||||||
|
|
||||||
#include "gob/gob.h"
|
#include "gob/gob.h"
|
||||||
@ -143,7 +144,13 @@ void CMPFile::loadCMP(Common::SeekableReadStream &cmp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CMPFile::loadRXY(Common::SeekableReadStream &rxy) {
|
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++) {
|
for (uint i = 0; i < _coordinates->size(); i++) {
|
||||||
const RXYFile::Coordinates &c = (*_coordinates)[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),
|
uint16 width, uint16 height, uint8 bpp) : _vm(vm),
|
||||||
_width(width), _height(height), _bpp(bpp), _hasPadding(false), _backdrop(0) {
|
_width(width), _height(height), _bpp(bpp), _hasPadding(false), _backdrop(0) {
|
||||||
|
|
||||||
Common::SeekableReadStream *dec = _vm->_dataIO->getFile(fileName);
|
bool bigEndian = false;
|
||||||
if (dec) {
|
Common::String endianFileName = fileName;
|
||||||
Common::SeekableSubReadStreamEndian sub(dec, 0, dec->size(), false, DisposeAfterUse::YES);
|
|
||||||
|
|
||||||
load(sub, fileName);
|
if ((_vm->getEndiannessMethod() == kEndiannessMethodAltFile) &&
|
||||||
return;
|
!_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;
|
||||||
Common::String alternateFileName = fileName;
|
alternateFileName.setChar('_', 0);
|
||||||
alternateFileName.setChar('_', 0);
|
|
||||||
|
|
||||||
dec = _vm->_dataIO->getFile(alternateFileName);
|
if (_vm->_dataIO->hasFile(alternateFileName)) {
|
||||||
if (dec) {
|
bigEndian = true;
|
||||||
Common::SeekableSubReadStreamEndian sub(dec, 0, dec->size(), true, DisposeAfterUse::YES);
|
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
|
// The big endian version pads a few fields to even size
|
||||||
_hasPadding = true;
|
_hasPadding = bigEndian;
|
||||||
|
|
||||||
load(sub, fileName);
|
load(sub, fileName);
|
||||||
return;
|
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() {
|
DECFile::~DECFile() {
|
||||||
|
@ -184,6 +184,10 @@ void GobEngine::validateVideoMode(int16 videoMode) {
|
|||||||
error("Video mode 0x%X is not supported", videoMode);
|
error("Video mode 0x%X is not supported", videoMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EndiannessMethod GobEngine::getEndiannessMethod() const {
|
||||||
|
return _endiannessMethod;
|
||||||
|
}
|
||||||
|
|
||||||
Endianness GobEngine::getEndianness() const {
|
Endianness GobEngine::getEndianness() const {
|
||||||
if ((getPlatform() == Common::kPlatformAmiga) ||
|
if ((getPlatform() == Common::kPlatformAmiga) ||
|
||||||
(getPlatform() == Common::kPlatformMacintosh) ||
|
(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
|
// 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;
|
_noMusic = MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK | MDT_MIDI | MDT_ADLIB)) == MT_NULL ? true : false;
|
||||||
|
|
||||||
|
_endiannessMethod = kEndiannessMethodSystem;
|
||||||
|
|
||||||
_global = new Global(this);
|
_global = new Global(this);
|
||||||
_util = new Util(this);
|
_util = new Util(this);
|
||||||
_dataIO = new DataIO();
|
_dataIO = new DataIO();
|
||||||
@ -433,6 +439,8 @@ Common::Error GobEngine::initGameParts() {
|
|||||||
_goblin = new Goblin_v1(this);
|
_goblin = new Goblin_v1(this);
|
||||||
_scenery = new Scenery_v1(this);
|
_scenery = new Scenery_v1(this);
|
||||||
_saveLoad = new SaveLoad_Geisha(this, _targetName.c_str());
|
_saveLoad = new SaveLoad_Geisha(this, _targetName.c_str());
|
||||||
|
|
||||||
|
_endiannessMethod = kEndiannessMethodAltFile;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kGameTypeFascination:
|
case kGameTypeFascination:
|
||||||
|
@ -149,6 +149,13 @@ enum Features {
|
|||||||
kFeaturesTrueColor = 1 << 7
|
kFeaturesTrueColor = 1 << 7
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum EndiannessMethod {
|
||||||
|
kEndiannessMethodLE, ///< Always little endian.
|
||||||
|
kEndiannessMethodBE, ///< Always big endian.
|
||||||
|
kEndiannessMethodSystem, ///< Follows system endianness.
|
||||||
|
kEndiannessMethodAltFile ///< Different endianness in alternate file.
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
kDebugFuncOp = 1 << 0,
|
kDebugFuncOp = 1 << 0,
|
||||||
kDebugDrawOp = 1 << 1,
|
kDebugDrawOp = 1 << 1,
|
||||||
@ -172,6 +179,8 @@ private:
|
|||||||
int32 _features;
|
int32 _features;
|
||||||
Common::Platform _platform;
|
Common::Platform _platform;
|
||||||
|
|
||||||
|
EndiannessMethod _endiannessMethod;
|
||||||
|
|
||||||
uint32 _pauseStart;
|
uint32 _pauseStart;
|
||||||
|
|
||||||
// Engine APIs
|
// Engine APIs
|
||||||
@ -232,6 +241,7 @@ public:
|
|||||||
|
|
||||||
void pauseGame();
|
void pauseGame();
|
||||||
|
|
||||||
|
EndiannessMethod getEndiannessMethod() const;
|
||||||
Endianness getEndianness() const;
|
Endianness getEndianness() const;
|
||||||
Common::Platform getPlatform() const;
|
Common::Platform getPlatform() const;
|
||||||
GameType getGameType() const;
|
GameType getGameType() const;
|
||||||
|
@ -21,12 +21,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common/stream.h"
|
#include "common/stream.h"
|
||||||
|
#include "common/substream.h"
|
||||||
|
|
||||||
#include "gob/rxyfile.h"
|
#include "gob/rxyfile.h"
|
||||||
|
|
||||||
namespace Gob {
|
namespace Gob {
|
||||||
|
|
||||||
RXYFile::RXYFile(Common::SeekableReadStream &rxy) : _width(0), _height(0) {
|
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);
|
load(rxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,22 +71,22 @@ const RXYFile::Coordinates &RXYFile::operator[](uint i) const {
|
|||||||
return _coords[i];
|
return _coords[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void RXYFile::load(Common::SeekableReadStream &rxy) {
|
void RXYFile::load(Common::SeekableSubReadStreamEndian &rxy) {
|
||||||
if (rxy.size() < 2)
|
if (rxy.size() < 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rxy.seek(0);
|
rxy.seek(0);
|
||||||
|
|
||||||
_realCount = rxy.readUint16LE();
|
_realCount = rxy.readUint16();
|
||||||
|
|
||||||
uint16 count = (rxy.size() - 2) / 8;
|
uint16 count = (rxy.size() - 2) / 8;
|
||||||
|
|
||||||
_coords.resize(count);
|
_coords.resize(count);
|
||||||
for (CoordArray::iterator c = _coords.begin(); c != _coords.end(); ++c) {
|
for (CoordArray::iterator c = _coords.begin(); c != _coords.end(); ++c) {
|
||||||
c->left = rxy.readUint16LE();
|
c->left = rxy.readUint16();
|
||||||
c->right = rxy.readUint16LE();
|
c->right = rxy.readUint16();
|
||||||
c->top = rxy.readUint16LE();
|
c->top = rxy.readUint16();
|
||||||
c->bottom = rxy.readUint16LE();
|
c->bottom = rxy.readUint16();
|
||||||
|
|
||||||
if (c->left != 0xFFFF) {
|
if (c->left != 0xFFFF) {
|
||||||
_width = MAX<uint16>(_width , c->right + 1);
|
_width = MAX<uint16>(_width , c->right + 1);
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
class SeekableReadStream;
|
class SeekableReadStream;
|
||||||
|
class SeekableSubReadStreamEndian;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Gob {
|
namespace Gob {
|
||||||
@ -46,6 +47,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
RXYFile(Common::SeekableReadStream &rxy);
|
RXYFile(Common::SeekableReadStream &rxy);
|
||||||
|
RXYFile(Common::SeekableSubReadStreamEndian &rxy);
|
||||||
RXYFile(uint16 width, uint16 height);
|
RXYFile(uint16 width, uint16 height);
|
||||||
~RXYFile();
|
~RXYFile();
|
||||||
|
|
||||||
@ -71,7 +73,7 @@ private:
|
|||||||
uint16 _height;
|
uint16 _height;
|
||||||
|
|
||||||
|
|
||||||
void load(Common::SeekableReadStream &rxy);
|
void load(Common::SeekableSubReadStreamEndian &rxy);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Gob
|
} // End of namespace Gob
|
||||||
|
Loading…
x
Reference in New Issue
Block a user