diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp index ce0480a7b28..80712cfe59d 100644 --- a/engines/sherlock/objects.cpp +++ b/engines/sherlock/objects.cpp @@ -674,6 +674,27 @@ void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) { _target = Common::String(buffer); } +void UseType::load3DO(Common::SeekableReadStream &s) { + char buffer[12]; + + _cAnimNum = s.readByte(); + _cAnimSpeed = s.readByte(); + if (_cAnimSpeed & 0x80) + _cAnimSpeed = -(_cAnimSpeed & 0x7f); + + for (int idx = 0; idx < NAMES_COUNT; ++idx) { + s.read(buffer, 12); + _names[idx] = Common::String(buffer); + } + + _useFlag = s.readSint16BE(); + + s.skip(6); + + s.read(buffer, 12); + _target = Common::String(buffer); +} + /*----------------------------------------------------------------*/ SherlockEngine *Object::_vm; @@ -781,6 +802,98 @@ void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) { } } +void Object::load3DO(Common::SeekableReadStream &s) { + char buffer[41]; + + _examine.clear(); + _sequences = nullptr; + _images = nullptr; + _imageFrame = nullptr; + + // on 3DO all of this data is reordered!!! + s.skip(4); + _sequenceOffset = s.readUint16LE(); // weird that this seems to be LE + s.seek(10, SEEK_CUR); + + _walkCount = 0; // ??? s.readByte(); + _allow = 0; // ??? s.readByte(); + _frameNumber = s.readSint16BE(); + _sequenceNumber = s.readSint16BE(); + _position.x = s.readSint16BE(); + _position.y = s.readSint16BE(); + _delta.x = s.readSint16BE(); + _delta.y = s.readSint16BE(); + _type = (SpriteType)s.readUint16BE(); + _oldPosition.x = s.readSint16BE(); + _oldPosition.y = s.readSint16BE(); + _oldSize.x = s.readUint16BE(); + _oldSize.y = s.readUint16BE(); + + _goto.x = s.readSint16BE(); + _goto.y = s.readSint16BE(); + _goto.x = _goto.x * FIXED_INT_MULTIPLIER / 100; + _goto.y = _goto.y * FIXED_INT_MULTIPLIER / 100; + + s.skip(16); // Unknown + +#if 0 + _pickup = s.readByte(); + _defaultCommand = s.readByte(); + _lookFlag = s.readSint16BE(); + _pickupFlag = s.readSint16BE(); + _requiredFlag = s.readSint16BE(); + _noShapeSize.x = s.readUint16BE(); + _noShapeSize.y = s.readUint16BE(); + _status = s.readUint16BE(); + _maxFrames = s.readUint16BE(); + + _aOpen.load(s); + + _aType = (AType)s.readByte(); + _lookFrames = s.readByte(); + _seqCounter = s.readByte(); + _lookPosition.x = s.readUint16BE() * FIXED_INT_MULTIPLIER / 100; + _lookPosition.y = s.readByte() * FIXED_INT_MULTIPLIER; + _lookFacing = s.readByte(); + _lookcAnim = s.readByte(); + + _aClose.load(s); + + _seqStack = s.readByte(); + _seqTo = s.readByte(); +#endif + warning("pos %d", s.pos()); + + _descOffset = s.readUint16BE(); + _seqCounter2 = 0; // ??? + _seqSize = s.readUint16BE(); + + s.skip(446); + +#if 0 + s.skip(1); + _aMove.load(s); + s.skip(8); + + for (int idx = 0; idx < 4; ++idx) + _use[idx].load(s, false); +#endif + + // 3DO: name is at the end + s.read(buffer, 12); + _name = Common::String(buffer); + s.read(buffer, 41); + _description = Common::String(buffer); + + s.skip(4); // Unknown + + // Probably those here?!?! + _misc = s.readByte(); + _flags = s.readByte(); + + s.skip(21); // Unknown +} + void Object::toggleHidden() { if (_type != HIDDEN && _type != HIDE_SHAPE && _type != INVALID) { if (_seqTo != 0) @@ -1516,6 +1629,33 @@ void CAnim::load(Common::SeekableReadStream &s, bool isRoseTattoo) { _teleportDir = s.readSint16LE(); } +void CAnim::load3DO(Common::SeekableReadStream &s) { + char buffer[12]; + s.read(buffer, 12); + _name = Common::String(buffer); + + s.read(_sequences, 30); + + _position.x = s.readSint16BE(); + _position.y = s.readSint16BE(); + + _size = s.readUint32BE(); + _type = (SpriteType)s.readUint16BE(); + _flags = s.readByte(); + + _goto.x = s.readSint16BE(); + _goto.y = s.readSint16BE(); + _gotoDir = s.readSint16BE(); + _teleportPos.x = s.readSint16BE(); + _teleportPos.y = s.readSint16BE(); + _goto.x = _goto.x * FIXED_INT_MULTIPLIER / 100; + _goto.y = _goto.y * FIXED_INT_MULTIPLIER / 100; + _teleportPos.x = _teleportPos.x * FIXED_INT_MULTIPLIER / 100; + _teleportPos.y = _teleportPos.y * FIXED_INT_MULTIPLIER / 100; + + _teleportDir = s.readSint16BE(); +} + /*----------------------------------------------------------------*/ CAnimStream::CAnimStream() { diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h index addadccd9d4..6561a370fad 100644 --- a/engines/sherlock/objects.h +++ b/engines/sherlock/objects.h @@ -159,6 +159,7 @@ struct UseType { * Load the data for the UseType */ void load(Common::SeekableReadStream &s, bool isRoseTattoo); + void load3DO(Common::SeekableReadStream &s); }; class BaseObject { @@ -344,6 +345,7 @@ public: * Load the data for the object */ void load(Common::SeekableReadStream &s, bool isRoseTattoo); + void load3DO(Common::SeekableReadStream &s); /** * Toggle the type of an object between hidden and active @@ -436,6 +438,7 @@ struct CAnim { * Load the data for the animation */ void load(Common::SeekableReadStream &s, bool isRoseTattoo); + void load3DO(Common::SeekableReadStream &s); }; class CAnimStream { diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp index c16d1f208be..028e2629997 100644 --- a/engines/sherlock/scene.cpp +++ b/engines/sherlock/scene.cpp @@ -84,6 +84,16 @@ void BgFileHeaderInfo::load(Common::SeekableReadStream &s) { _filename = Common::String(buffer); } +void BgFileHeaderInfo::load3DO(Common::SeekableReadStream &s) { + _filesize = s.readUint32BE(); + _maxFrames = s.readByte(); + + char buffer[9]; + s.read(buffer, 9); + _filename = Common::String(buffer); + s.skip(2); // only on 3DO! +} + /*----------------------------------------------------------------*/ void Exit::load(Common::SeekableReadStream &s, bool isRoseTattoo) { @@ -121,6 +131,13 @@ void SceneEntry::load(Common::SeekableReadStream &s) { _allow = s.readByte(); } +void SceneEntry::load3DO(Common::SeekableReadStream &s) { + _startPosition.x = s.readSint16BE(); + _startPosition.y = s.readSint16BE(); + _startDir = s.readByte(); + _allow = s.readByte(); +} + void SceneSound::load(Common::SeekableReadStream &s) { char buffer[9]; s.read(buffer, 8); @@ -130,6 +147,10 @@ void SceneSound::load(Common::SeekableReadStream &s) { _priority = s.readByte(); } +void SceneSound::load3DO(Common::SeekableReadStream &s) { + load(s); +} + /*----------------------------------------------------------------*/ int ObjectArray::indexOf(const Object &obj) const { @@ -285,140 +306,376 @@ bool Scene::loadScene(const Common::String &filename) { // Load the room resource file for the scene // - Common::String rrmFile = filename + ".rrm"; - flag = _vm->_res->exists(rrmFile); - if (flag) { - Common::SeekableReadStream *rrmStream = _vm->_res->load(rrmFile); + if (_vm->getPlatform() != Common::kPlatform3DO) { + // PC version + Common::String rrmFile = filename + ".rrm"; + flag = _vm->_res->exists(rrmFile); + if (flag) { + Common::SeekableReadStream *rrmStream = _vm->_res->load(rrmFile); - rrmStream->seek(39); - if (IS_SERRATED_SCALPEL) { - _version = rrmStream->readByte(); - _lzwMode = _version == 10; - } else { - _lzwMode = rrmStream->readByte() > 0; - } - - // Go to header and read it in - rrmStream->seek(rrmStream->readUint32LE()); - - BgFileHeader bgHeader; - bgHeader.load(*rrmStream, IS_ROSE_TATTOO); - _invGraphicItems = bgHeader._numImages + 1; - - if (IS_ROSE_TATTOO) { - screen.initPaletteFade(bgHeader._bytesWritten); - rrmStream->read(screen._cMap, PALETTE_SIZE); - screen.translatePalette(screen._cMap); - - paletteLoaded(); - - // Read in background - if (_lzwMode) { - res.decompress(*rrmStream, (byte *)screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT); + rrmStream->seek(39); + if (IS_SERRATED_SCALPEL) { + _version = rrmStream->readByte(); + _lzwMode = _version == 10; } else { - rrmStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT); + _lzwMode = rrmStream->readByte() > 0; } - } - // Read in the shapes header info - Common::Array bgInfo; - bgInfo.resize(bgHeader._numStructs); + // Go to header and read it in + rrmStream->seek(rrmStream->readUint32LE()); - for (uint idx = 0; idx < bgInfo.size(); ++idx) - bgInfo[idx].load(*rrmStream); + BgFileHeader bgHeader; + bgHeader.load(*rrmStream, IS_ROSE_TATTOO); + _invGraphicItems = bgHeader._numImages + 1; - // Read information - if (IS_ROSE_TATTOO) { - // Load shapes - Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream : res.decompress(*rrmStream, bgHeader._numStructs * 625); + if (IS_ROSE_TATTOO) { + screen.initPaletteFade(bgHeader._bytesWritten); + rrmStream->read(screen._cMap, PALETTE_SIZE); + screen.translatePalette(screen._cMap); - _bgShapes.resize(bgHeader._numStructs); - for (int idx = 0; idx < bgHeader._numStructs; ++idx) - _bgShapes[idx].load(*infoStream, _vm->getGameID() == GType_RoseTattoo); + paletteLoaded(); - if (_lzwMode) - delete infoStream; + // Read in background + if (_lzwMode) { + res.decompress(*rrmStream, (byte *)screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT); + } else { + rrmStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT); + } + } - // Load description text - _descText.resize(bgHeader._descSize); - if (_lzwMode) - res.decompress(*rrmStream, (byte *)&_descText[0], bgHeader._descSize); - else - rrmStream->read(&_descText[0], bgHeader._descSize); + // Read in the shapes header info + Common::Array bgInfo; + bgInfo.resize(bgHeader._numStructs); - // Load sequences - _sequenceBuffer.resize(bgHeader._seqSize); - if (_lzwMode) - res.decompress(*rrmStream, &_sequenceBuffer[0], bgHeader._seqSize); - else - rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize); - } else if (!_lzwMode) { - // Serrated Scalpel uncompressed info - _bgShapes.resize(bgHeader._numStructs); - for (int idx = 0; idx < bgHeader._numStructs; ++idx) - _bgShapes[idx].load(*rrmStream, false); + for (uint idx = 0; idx < bgInfo.size(); ++idx) + bgInfo[idx].load(*rrmStream); - if (bgHeader._descSize) { + // Read information + if (IS_ROSE_TATTOO) { + // Load shapes + Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream : res.decompress(*rrmStream, bgHeader._numStructs * 625); + + _bgShapes.resize(bgHeader._numStructs); + for (int idx = 0; idx < bgHeader._numStructs; ++idx) + _bgShapes[idx].load(*infoStream, _vm->getGameID() == GType_RoseTattoo); + + if (_lzwMode) + delete infoStream; + + // Load description text _descText.resize(bgHeader._descSize); - rrmStream->read(&_descText[0], bgHeader._descSize); - } + if (_lzwMode) + res.decompress(*rrmStream, (byte *)&_descText[0], bgHeader._descSize); + else + rrmStream->read(&_descText[0], bgHeader._descSize); - if (bgHeader._seqSize) { + // Load sequences _sequenceBuffer.resize(bgHeader._seqSize); - rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize); - } - } else { - // Serrated Scalpel compressed info - Common::SeekableReadStream *infoStream; + if (_lzwMode) + res.decompress(*rrmStream, &_sequenceBuffer[0], bgHeader._seqSize); + else + rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize); + } else if (!_lzwMode) { + // Serrated Scalpel uncompressed info + _bgShapes.resize(bgHeader._numStructs); + for (int idx = 0; idx < bgHeader._numStructs; ++idx) + _bgShapes[idx].load(*rrmStream, false); - // Read shapes - infoStream = Resources::decompressLZ(*rrmStream, bgHeader._numStructs * 569); + if (bgHeader._descSize) { + _descText.resize(bgHeader._descSize); + rrmStream->read(&_descText[0], bgHeader._descSize); + } - _bgShapes.resize(bgHeader._numStructs); - for (int idx = 0; idx < bgHeader._numStructs; ++idx) - _bgShapes[idx].load(*infoStream, false); + if (bgHeader._seqSize) { + _sequenceBuffer.resize(bgHeader._seqSize); + rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize); + } + } else { + // Serrated Scalpel compressed info + Common::SeekableReadStream *infoStream; - delete infoStream; + // Read shapes + infoStream = Resources::decompressLZ(*rrmStream, bgHeader._numStructs * 569); - // Read description texts - if (bgHeader._descSize) { - infoStream = Resources::decompressLZ(*rrmStream, bgHeader._descSize); - - _descText.resize(bgHeader._descSize); - infoStream->read(&_descText[0], bgHeader._descSize); + _bgShapes.resize(bgHeader._numStructs); + for (int idx = 0; idx < bgHeader._numStructs; ++idx) + _bgShapes[idx].load(*infoStream, false); delete infoStream; + + // Read description texts + if (bgHeader._descSize) { + infoStream = Resources::decompressLZ(*rrmStream, bgHeader._descSize); + + _descText.resize(bgHeader._descSize); + infoStream->read(&_descText[0], bgHeader._descSize); + + delete infoStream; + } + + // Read sequences + if (bgHeader._seqSize) { + infoStream = Resources::decompressLZ(*rrmStream, bgHeader._seqSize); + + _sequenceBuffer.resize(bgHeader._seqSize); + infoStream->read(&_sequenceBuffer[0], bgHeader._seqSize); + + delete infoStream; + } } - // Read sequences - if (bgHeader._seqSize) { - infoStream = Resources::decompressLZ(*rrmStream, bgHeader._seqSize); + // Set up the list of images used by the scene + _images.resize(bgHeader._numImages + 1); + for (int idx = 0; idx < bgHeader._numImages; ++idx) { + _images[idx + 1]._filesize = bgInfo[idx]._filesize; + _images[idx + 1]._maxFrames = bgInfo[idx]._maxFrames; - _sequenceBuffer.resize(bgHeader._seqSize); - infoStream->read(&_sequenceBuffer[0], bgHeader._seqSize); + // Read in the image data + Common::SeekableReadStream *imageStream = _lzwMode ? + res.decompress(*rrmStream, bgInfo[idx]._filesize) : + rrmStream->readStream(bgInfo[idx]._filesize); - delete infoStream; + _images[idx + 1]._images = new ImageFile(*imageStream); + + delete imageStream; } + + // Set up the bgShapes + for (int idx = 0; idx < bgHeader._numStructs; ++idx) { + _bgShapes[idx]._images = _images[_bgShapes[idx]._misc]._images; + _bgShapes[idx]._imageFrame = !_bgShapes[idx]._images ? (ImageFrame *)nullptr : + &(*_bgShapes[idx]._images)[0]; + + _bgShapes[idx]._examine = Common::String(&_descText[_bgShapes[idx]._descOffset]); + _bgShapes[idx]._sequences = &_sequenceBuffer[_bgShapes[idx]._sequenceOffset]; + _bgShapes[idx]._misc = 0; + _bgShapes[idx]._seqCounter = 0; + _bgShapes[idx]._seqCounter2 = 0; + _bgShapes[idx]._seqStack = 0; + _bgShapes[idx]._frameNumber = -1; + _bgShapes[idx]._oldPosition = Common::Point(0, 0); + _bgShapes[idx]._oldSize = Common::Point(1, 1); + } + + // Load in cAnim list + _cAnim.clear(); + if (bgHeader._numcAnimations) { + int animSize = IS_SERRATED_SCALPEL ? 65 : 47; + Common::SeekableReadStream *canimStream = _lzwMode ? + res.decompress(*rrmStream, animSize * bgHeader._numcAnimations) : + rrmStream->readStream(animSize * bgHeader._numcAnimations); + + _cAnim.resize(bgHeader._numcAnimations); + for (uint idx = 0; idx < _cAnim.size(); ++idx) + _cAnim[idx].load(*canimStream, IS_ROSE_TATTOO); + + delete canimStream; + } + + // Read in the room bounding areas + int size = rrmStream->readUint16LE(); + Common::SeekableReadStream *boundsStream = !_lzwMode ? rrmStream : + res.decompress(*rrmStream, size); + + _zones.resize(size / 10); + for (uint idx = 0; idx < _zones.size(); ++idx) { + _zones[idx].left = boundsStream->readSint16LE(); + _zones[idx].top = boundsStream->readSint16LE(); + _zones[idx].setWidth(boundsStream->readSint16LE() + 1); + _zones[idx].setHeight(boundsStream->readSint16LE() + 1); + boundsStream->skip(2); // Skip unused scene number field + } + + if (_lzwMode) + delete boundsStream; + + // Ensure we've reached the path version byte + if (rrmStream->readByte() != (IS_SERRATED_SCALPEL ? 254 : 251)) + error("Invalid scene path data"); + + // Load the walk directory + assert(_zones.size() < MAX_ZONES); + for (uint idx1 = 0; idx1 < _zones.size(); ++idx1) { + for (uint idx2 = 0; idx2 < _zones.size(); ++idx2) + _walkDirectory[idx1][idx2] = rrmStream->readSint16LE(); + } + + // Read in the walk data + size = rrmStream->readUint16LE(); + Common::SeekableReadStream *walkStream = !_lzwMode ? rrmStream : + res.decompress(*rrmStream, size); + + _walkData.resize(size); + walkStream->read(&_walkData[0], size); + + if (_lzwMode) + delete walkStream; + + if (IS_ROSE_TATTOO) { + // Read in the entrance + _entrance.load(*rrmStream); + + // Load scale zones + _scaleZones.resize(rrmStream->readByte()); + for (uint idx = 0; idx < _scaleZones.size(); ++idx) + _scaleZones[idx].load(*rrmStream); + } + + // Read in the exits + _exitZone = -1; + int numExits = rrmStream->readByte(); + _exits.resize(numExits); + + for (int idx = 0; idx < numExits; ++idx) + _exits[idx].load(*rrmStream, IS_ROSE_TATTOO); + + if (IS_SERRATED_SCALPEL) + // Read in the entrance + _entrance.load(*rrmStream); + + // Initialize sound list + int numSounds = rrmStream->readByte(); + _sounds.resize(numSounds); + + for (int idx = 0; idx < numSounds; ++idx) + _sounds[idx].load(*rrmStream); + + loadSceneSounds(); + + if (IS_ROSE_TATTOO) { + // Load the object sound list + char buffer[27]; + + _objSoundList.resize(rrmStream->readUint16LE()); + for (uint idx = 0; idx < _objSoundList.size(); ++idx) { + rrmStream->read(buffer, 27); + _objSoundList[idx] = Common::String(buffer); + } + } else { + // Read in palette + rrmStream->read(screen._cMap, PALETTE_SIZE); + screen.translatePalette(screen._cMap); + Common::copy(screen._cMap, screen._cMap + PALETTE_SIZE, screen._sMap); + + // Read in the background + Common::SeekableReadStream *bgStream = !_lzwMode ? rrmStream : + res.decompress(*rrmStream, SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT); + + bgStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT); + + if (_lzwMode) + delete bgStream; + } + + // Backup the image and set the palette + screen._backBuffer2.blitFrom(screen._backBuffer1); + screen.setPalette(screen._cMap); + + delete rrmStream; } - // Set up the list of images used by the scene - _images.resize(bgHeader._numImages + 1); - for (int idx = 0; idx < bgHeader._numImages; ++idx) { + } else { + // === 3DO version === + Common::String roomFile = "rooms/" + filename + ".rrm"; + flag = _vm->_res->exists(roomFile); + if (!flag) + error("loadScene: 3DO room file not found"); + + Common::SeekableReadStream *roomStream = _vm->_res->load(roomFile); + + // Read 3DO header + roomStream->skip(4); // UINT32: offset graphic data? + uint16 header3DO_numStructs = roomStream->readUint16BE(); + uint16 header3DO_numImages = roomStream->readUint16BE(); + uint16 header3DO_numAnimations = roomStream->readUint16BE(); + roomStream->skip(6); + + uint32 header3DO_bgInfo_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_bgInfo_size = roomStream->readUint32BE(); + uint32 header3DO_bgShapes_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_bgShapes_size = roomStream->readUint32BE(); + uint32 header3DO_descriptions_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_descriptions_size = roomStream->readUint32BE(); + uint32 header3DO_sequence_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_sequence_size = roomStream->readUint32BE(); + uint32 header3DO_cAnim_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_cAnim_size = roomStream->readUint32BE(); + uint32 header3DO_roomBounding_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_roomBounding_size = roomStream->readUint32BE(); + uint32 header3DO_walkDirectory_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_walkDirectory_size = roomStream->readUint32BE(); + uint32 header3DO_walkData_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_walkData_size = roomStream->readUint32BE(); + uint32 header3DO_exits_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_exits_size = roomStream->readUint32BE(); + uint32 header3DO_entranceData_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_entranceData_size = roomStream->readUint32BE(); + uint32 header3DO_soundList_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_soundList_size = roomStream->readUint32BE(); + uint32 header3DO_unknown_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_unknown_size = roomStream->readUint32BE(); + uint32 header3DO_bgGraphicData_offset = roomStream->readUint32BE() + 0x80; + uint32 header3DO_bgGraphicData_size = roomStream->readUint32BE(); + + int32 header3DO_soundList_count = header3DO_soundList_size / 9; + + _invGraphicItems = header3DO_numImages + 1; + + // === BGINFO === read in the shapes header info + Common::Array bgInfo; + + roomStream->seek(header3DO_bgInfo_offset); + bgInfo.resize(header3DO_numStructs); + for (uint idx = 0; idx < bgInfo.size(); ++idx) + bgInfo[idx].load3DO(*roomStream); + + // === BGSHAPES === read in the shapes info + roomStream->seek(header3DO_bgShapes_offset); + _bgShapes.resize(header3DO_numStructs); + for (int idx = 0; idx < header3DO_numStructs; ++idx) + _bgShapes[idx].load3DO(*roomStream); + + // === DESCRIPTION === read description text + if (header3DO_descriptions_size) { + roomStream->seek(header3DO_descriptions_offset); + _descText.resize(header3DO_descriptions_size); + roomStream->read(&_descText[0], header3DO_descriptions_size); + } + + // === SEQUENCE === read sequence buffer + if (header3DO_sequence_size) { + roomStream->seek(header3DO_sequence_offset); + _sequenceBuffer.resize(header3DO_sequence_size); + roomStream->read(&_sequenceBuffer[0], header3DO_sequence_size); + } + + // === IMAGES === set up the list of images used by the scene + roomStream->seek(header3DO_bgGraphicData_offset); + _images.resize(header3DO_numImages + 1); + for (int idx = 0; idx < header3DO_numImages; ++idx) { _images[idx + 1]._filesize = bgInfo[idx]._filesize; _images[idx + 1]._maxFrames = bgInfo[idx]._maxFrames; + // Read the image data + // It seems it's a 8 byte header per frame + // followed by a copy of the cel header + // which is then followed by cel data + // TODO + warning("image %d, maxFrames %d", idx, bgInfo[idx]._maxFrames); + warning("size %d", bgInfo[idx]._filesize); + // Read in the image data - Common::SeekableReadStream *imageStream = _lzwMode ? - res.decompress(*rrmStream, bgInfo[idx]._filesize) : - rrmStream->readStream(bgInfo[idx]._filesize); + //Common::SeekableReadStream *imageStream = roomStream->readStream(bgInfo[idx]._filesize); - _images[idx + 1]._images = new ImageFile(*imageStream); + //_images[idx + 1]._images = new ImageFile(*imageStream); - delete imageStream; + //delete imageStream; + warning("end"); } - // Set up the bgShapes - for (int idx = 0; idx < bgHeader._numStructs; ++idx) { + // === BGSHAPES === Set up the bgShapes + for (int idx = 0; idx < header3DO_numStructs; ++idx) { + warning("%d", _bgShapes[idx]._misc); _bgShapes[idx]._images = _images[_bgShapes[idx]._misc]._images; _bgShapes[idx]._imageFrame = !_bgShapes[idx]._images ? (ImageFrame *)nullptr : &(*_bgShapes[idx]._images)[0]; @@ -434,121 +691,73 @@ bool Scene::loadScene(const Common::String &filename) { _bgShapes[idx]._oldSize = Common::Point(1, 1); } - // Load in cAnim list + // === CANIM === read cAnim list _cAnim.clear(); - if (bgHeader._numcAnimations) { - int animSize = IS_SERRATED_SCALPEL ? 65 : 47; - Common::SeekableReadStream *canimStream = _lzwMode ? - res.decompress(*rrmStream, animSize * bgHeader._numcAnimations) : - rrmStream->readStream(animSize * bgHeader._numcAnimations); + if (header3DO_numAnimations) { + int animSize = 65; - _cAnim.resize(bgHeader._numcAnimations); + roomStream->seek(header3DO_cAnim_offset); + Common::SeekableReadStream *canimStream = roomStream->readStream(animSize * header3DO_numAnimations); + + _cAnim.resize(header3DO_numAnimations); for (uint idx = 0; idx < _cAnim.size(); ++idx) - _cAnim[idx].load(*canimStream, IS_ROSE_TATTOO); + _cAnim[idx].load3DO(*canimStream); delete canimStream; } - // Read in the room bounding areas - int size = rrmStream->readUint16LE(); - Common::SeekableReadStream *boundsStream = !_lzwMode ? rrmStream : - res.decompress(*rrmStream, size); + // === BOUNDING AREAS === Read in the room bounding areas + int roomBoundingCount = header3DO_roomBounding_size / 12; - _zones.resize(size / 10); + roomStream->seek(header3DO_roomBounding_offset); + _zones.resize(roomBoundingCount); for (uint idx = 0; idx < _zones.size(); ++idx) { - _zones[idx].left = boundsStream->readSint16LE(); - _zones[idx].top = boundsStream->readSint16LE(); - _zones[idx].setWidth(boundsStream->readSint16LE() + 1); - _zones[idx].setHeight(boundsStream->readSint16LE() + 1); - boundsStream->skip(2); // Skip unused scene number field + _zones[idx].left = roomStream->readSint16BE(); + _zones[idx].top = roomStream->readSint16BE(); + _zones[idx].setWidth(roomStream->readSint16BE() + 1); + _zones[idx].setHeight(roomStream->readSint16BE() + 1); + roomStream->skip(4); // skip UINT32 } - if (_lzwMode) - delete boundsStream; - - // Ensure we've reached the path version byte - if (rrmStream->readByte() != (IS_SERRATED_SCALPEL ? 254 : 251)) - error("Invalid scene path data"); - - // Load the walk directory + // === WALK DIRECTORY === Load the walk directory + roomStream->seek(header3DO_walkDirectory_offset); assert(_zones.size() < MAX_ZONES); for (uint idx1 = 0; idx1 < _zones.size(); ++idx1) { for (uint idx2 = 0; idx2 < _zones.size(); ++idx2) - _walkDirectory[idx1][idx2] = rrmStream->readSint16LE(); + _walkDirectory[idx1][idx2] = roomStream->readSint16BE(); } - // Read in the walk data - size = rrmStream->readUint16LE(); - Common::SeekableReadStream *walkStream = !_lzwMode ? rrmStream : - res.decompress(*rrmStream, size); + // === WALK DATA === Read in the walk data + roomStream->seek(header3DO_walkData_offset); + _walkData.resize(header3DO_walkData_size); + roomStream->read(&_walkData[0], header3DO_walkData_size); - _walkData.resize(size); - walkStream->read(&_walkData[0], size); - - if (_lzwMode) - delete walkStream; - - if (IS_ROSE_TATTOO) { - // Read in the entrance - _entrance.load(*rrmStream); - - // Load scale zones - _scaleZones.resize(rrmStream->readByte()); - for (uint idx = 0; idx < _scaleZones.size(); ++idx) - _scaleZones[idx].load(*rrmStream); - } - - // Read in the exits + // === EXITS === Read in the exits _exitZone = -1; - int numExits = rrmStream->readByte(); - _exits.resize(numExits); + _exits.resize(header3DO_exits_size); // TODO!!!! - for (int idx = 0; idx < numExits; ++idx) - _exits[idx].load(*rrmStream, IS_ROSE_TATTOO); + //for (int idx = 0; idx < numExits; ++idx) + // _exits[idx].load(*rrmStream, IS_ROSE_TATTOO); - if (IS_SERRATED_SCALPEL) - // Read in the entrance - _entrance.load(*rrmStream); + // === ENTRANCE === Read in the entrance + roomStream->seek(header3DO_entranceData_offset); + _entrance.load(*roomStream); - // Initialize sound list - int numSounds = rrmStream->readByte(); - _sounds.resize(numSounds); + // === SOUND LIST === Initialize sound list + roomStream->seek(header3DO_soundList_offset); + _sounds.resize(header3DO_soundList_count); + for (int idx = 0; idx < header3DO_soundList_count; ++idx) + _sounds[idx].load3DO(*roomStream); - for (int idx = 0; idx < numSounds; ++idx) - _sounds[idx].load(*rrmStream); + // === BACKGROUND PICTURE === + // load from file rooms\[filename].bg + // it's uncompressed 15-bit RGB555 data - loadSceneSounds(); - if (IS_ROSE_TATTOO) { - // Load the object sound list - char buffer[27]; - - _objSoundList.resize(rrmStream->readUint16LE()); - for (uint idx = 0; idx < _objSoundList.size(); ++idx) { - rrmStream->read(buffer, 27); - _objSoundList[idx] = Common::String(buffer); - } - } else { - // Read in palette - rrmStream->read(screen._cMap, PALETTE_SIZE); - screen.translatePalette(screen._cMap); - Common::copy(screen._cMap, screen._cMap + PALETTE_SIZE, screen._sMap); - // Read in the background - Common::SeekableReadStream *bgStream = !_lzwMode ? rrmStream : - res.decompress(*rrmStream, SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT); - bgStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT); - if (_lzwMode) - delete bgStream; - } - // Backup the image and set the palette - screen._backBuffer2.blitFrom(screen._backBuffer1); - screen.setPalette(screen._cMap); - - delete rrmStream; } // Handle drawing any on-screen interface diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h index b8b2d2c9b6c..8051d45c2d4 100644 --- a/engines/sherlock/scene.h +++ b/engines/sherlock/scene.h @@ -72,6 +72,7 @@ struct BgFileHeaderInfo { * Load the data for the object */ void load(Common::SeekableReadStream &s); + void load3DO(Common::SeekableReadStream &s); }; class Exit: public Common::Rect { @@ -99,6 +100,7 @@ struct SceneEntry { * Load the data for the object */ void load(Common::SeekableReadStream &s); + void load3DO(Common::SeekableReadStream &s); }; struct SceneSound { @@ -109,6 +111,7 @@ struct SceneSound { * Load the data for the object */ void load(Common::SeekableReadStream &s); + void load3DO(Common::SeekableReadStream &s); }; class ObjectArray : public Common::Array {