void ActorType::load(byte *dataStart, Common::SeekableReadStream &stream) { _actorTypeId = stream.readUint32LE(); _surfInfo.load(stream); uint32 pointsConfigOffs = stream.readUint32LE(); uint namedPointsCount = stream.readUint16LE(); stream.skip(2); // Skip padding uint32 namedPointsOffs = stream.readUint32LE(); _color.r = stream.readByte(); _color.g = stream.readByte(); _color.b = stream.readByte(); stream.readByte(); // Skip padding _scale = stream.readByte(); _priority = stream.readByte(); _value1E = stream.readUint16LE(); _pathWalkPointsIndex = stream.readUint16LE(); _scaleLayerIndex = stream.readUint16LE(); _pathWalkRectIndex = stream.readUint16LE(); _priorityLayerIndex = stream.readUint16LE(); _regionLayerIndex = stream.readUint16LE(); _flags = stream.readUint16LE(); _pointsConfig = dataStart + pointsConfigOffs; stream.seek(namedPointsOffs); _namedPoints.load(namedPointsCount, stream); debug(5, "ActorType::load() _actorTypeId: %08X; _color(%d,%d,%d); _scale: %d; _priority: %d; _value1E: %d", _actorTypeId, _color.r, _color.g, _color.b, _scale, _priority, _value1E); debug(5, "ActorType::load() _pathWalkPointsIndex: %d; _scaleLayerIndex: %d; _pathWalkRectIndex: %d", _pathWalkPointsIndex, _scaleLayerIndex, _pathWalkRectIndex); debug(5, "ActorType::load() _priorityLayerIndex: %d; _regionLayerIndex: %d; _flags: %04X", _priorityLayerIndex, _regionLayerIndex,_flags); }
void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool animImages) { loadPalette(stream); int streamSize = stream.size(); while (stream.pos() < streamSize) { ImageFrame frame; frame._width = stream.readUint16LE() + 1; frame._height = stream.readUint16LE() + 1; frame._paletteBase = stream.readByte(); if (animImages) { // Animation cutscene image files use a 16-bit x offset frame._offset.x = stream.readUint16LE(); frame._rleEncoded = (frame._offset.x & 0xff) == 1; frame._offset.y = stream.readByte(); } else { // Standard image files have a separate byte for the RLE flag, and an 8-bit X offset frame._rleEncoded = stream.readByte() == 1; frame._offset.x = stream.readByte(); frame._offset.y = stream.readByte(); } frame._rleEncoded = !skipPalette && frame._rleEncoded; if (frame._paletteBase) { // Nibble packed frame data frame._size = (frame._width * frame._height) / 2; } else if (frame._rleEncoded) { // This size includes the header size, which we subtract frame._size = stream.readUint16LE() - 11; frame._rleMarker = stream.readByte(); } else { // Uncompressed data frame._size = frame._width * frame._height; } // Load data for frame and decompress it byte *data = new byte[frame._size + 4]; stream.read(data, frame._size); Common::fill(data + frame._size, data + frame._size + 4, 0); frame.decompressFrame(data, IS_ROSE_TATTOO); delete[] data; push_back(frame); } }
bool TGADecoder::readDataRLE(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { // RLE-TrueColor / RLE-Black/White if (imageType == TYPE_RLE_TRUECOLOR || imageType == TYPE_RLE_BW || imageType == TYPE_RLE_CMAP) { _surface.create(_surface.w, _surface.h, _format); uint32 count = _surface.w * _surface.h; byte *data = (byte *)_surface.getPixels(); while (count > 0) { uint32 header = tga.readByte(); byte type = (header & 0x80) >> 7; uint32 rleCount = (header & 0x7F) + 1; // RLE-packet if (type == 1) { if (pixelDepth == 32 && imageType == TYPE_RLE_TRUECOLOR) { uint32 color = tga.readUint32LE(); while (rleCount-- > 0) { *((uint32 *)data) = color; data += 4; count--; } } else if (pixelDepth == 24 && imageType == TYPE_RLE_TRUECOLOR) { byte r = tga.readByte(); byte g = tga.readByte(); byte b = tga.readByte(); while (rleCount-- > 0) { #ifdef SCUMM_LITTLE_ENDIAN *data++ = r; *data++ = g; *data++ = b; #else *data++ = b; *data++ = g; *data++ = r; #endif count--; } } else if (pixelDepth == 16 && imageType == TYPE_RLE_TRUECOLOR) { const uint16 rgb = tga.readUint16LE(); while (rleCount-- > 0) { *((uint16 *)data) = rgb; data += 2; count--; } } else if (pixelDepth == 8 && imageType == TYPE_RLE_BW) { byte color = tga.readByte(); while (rleCount-- > 0) { *data++ = color; *data++ = color; *data++ = color; *data++ = color; count--; } } else if (pixelDepth == 8 && imageType == TYPE_RLE_CMAP) { byte index = tga.readByte(); while (rleCount-- > 0) { *data++ = index; count--; } } else { warning("Unhandled pixel-depth for image-type 10"); return false; } // Raw-packet } else if (type == 0) { if (pixelDepth == 32 && imageType == TYPE_RLE_TRUECOLOR) { while (rleCount-- > 0) { uint32 color = tga.readUint32LE(); *((uint32 *)data) = color; data += 4; count--; } } else if (pixelDepth == 24 && imageType == TYPE_RLE_TRUECOLOR) { while (rleCount-- > 0) { byte r = tga.readByte(); byte g = tga.readByte(); byte b = tga.readByte(); #ifdef SCUMM_LITTLE_ENDIAN *data++ = r; *data++ = g; *data++ = b; #else *data++ = b; *data++ = g; *data++ = r; #endif count--; } } else if (pixelDepth == 16 && imageType == TYPE_RLE_TRUECOLOR) { while (rleCount-- > 0) { *((uint16 *)data) = tga.readUint16LE(); data += 2; count--; } } else if (pixelDepth == 8 && imageType == TYPE_RLE_BW) { while (rleCount-- > 0) { byte color = tga.readByte(); *data++ = color; *data++ = color; *data++ = color; *data++ = color; count--; } } else if (pixelDepth == 8 && imageType == TYPE_RLE_CMAP) { while (rleCount-- > 0) { byte index = tga.readByte(); *data++ = index; count--; } } else { warning("Unhandled pixel-depth for image-type 10"); return false; } } else { warning("Unknown header for RLE-packet %d", type); return false; } } } else {
bool PersistenceService::saveGame(uint slotID, const Common::String &screenshotFilename) { // FIXME: This code is a hack which bypasses the savefile API, // and should eventually be removed. // Überprüfen, ob die Slot-ID zulässig ist. if (slotID >= SLOT_COUNT) { error("Tried to save to an invalid slot (%d). Only slot ids form 0 to %d are allowed.", slotID, SLOT_COUNT - 1); return false; } // Dateinamen erzeugen. Common::String filename = generateSavegameFilename(slotID); // Spielstanddatei öffnen und die Headerdaten schreiben. Common::SaveFileManager *sfm = g_system->getSavefileManager(); Common::OutSaveFile *file = sfm->openForSaving(filename); file->writeString(FILE_MARKER); file->writeByte(0); file->writeString(VERSIONID); file->writeByte(0); char buf[20]; snprintf(buf, 20, "%d", VERSIONNUM); file->writeString(buf); file->writeByte(0); TimeDate dt; g_system->getTimeAndDate(dt); file->writeString(formatTimestamp(dt)); file->writeByte(0); if (file->err()) { error("Unable to write header data to savegame file \"%s\".", filename.c_str()); } // Alle notwendigen Module persistieren. OutputPersistenceBlock writer; bool success = true; success &= Kernel::getInstance()->getScript()->persist(writer); success &= RegionRegistry::instance().persist(writer); success &= Kernel::getInstance()->getGfx()->persist(writer); success &= Kernel::getInstance()->getSfx()->persist(writer); success &= Kernel::getInstance()->getInput()->persist(writer); if (!success) { error("Unable to persist modules for savegame file \"%s\".", filename.c_str()); } // Write the save game data uncompressed, since the final saved game will be // compressed anyway. char sBuffer[10]; snprintf(sBuffer, 10, "%u", writer.getDataSize()); file->writeString(sBuffer); file->writeByte(0); snprintf(sBuffer, 10, "%u", writer.getDataSize()); file->writeString(sBuffer); file->writeByte(0); file->write(writer.getData(), writer.getDataSize()); // Get the screenshot Common::SeekableReadStream *thumbnail = Kernel::getInstance()->getGfx()->getThumbnail(); if (thumbnail) { byte *buffer = new byte[FILE_COPY_BUFFER_SIZE]; thumbnail->seek(0, SEEK_SET); while (!thumbnail->eos()) { int bytesRead = thumbnail->read(&buffer[0], FILE_COPY_BUFFER_SIZE); file->write(&buffer[0], bytesRead); } delete[] buffer; } else { warning("The screenshot file \"%s\" does not exist. Savegame is written without a screenshot.", filename.c_str()); } file->finalize(); delete file; // Savegameinformationen für diesen Slot aktualisieren. _impl->readSlotSavegameInformation(slotID); // Empty the cache, to remove old thumbnails Kernel::getInstance()->getResourceManager()->emptyThumbnailCache(); // Erfolg signalisieren. return true; }
int TattooMap::show() { Debugger &debugger = *_vm->_debugger; Events &events = *_vm->_events; Music &music = *_vm->_music; Resources &res = *_vm->_res; TattooScene &scene = *(TattooScene *)_vm->_scene; Screen &screen = *_vm->_screen; int result = 0; // Check if we need to keep track of how many times player has been to the map for (uint idx = 0; idx < scene._sceneTripCounters.size(); ++idx) { SceneTripEntry &entry = scene._sceneTripCounters[idx]; if (entry._sceneNumber == OVERHEAD_MAP || entry._sceneNumber == OVERHEAD_MAP2) { if (--entry._numTimes == 0) { _vm->setFlagsDirect(entry._flag); scene._sceneTripCounters.remove_at(idx); } } } if (music._midiOption) { // See if Holmes or Watson is the active character Common::String song; if (_vm->readFlags(FLAG_PLAYER_IS_HOLMES)) // Player is Holmes song = "Cue9"; else if (_vm->readFlags(FLAG_ALT_MAP_MUSIC)) song = "Cue8"; else song = "Cue7"; if (music.loadSong(song)) { music.setMIDIVolume(music._musicVolume); if (music._musicOn) music.startSong(); } } screen.initPaletteFade(1364485); // Load the custom mouse cursors for the map ImageFile cursors("omouse.vgs"); events.setCursor(cursors[0]._frame); events.warpMouse(Common::Point(SHERLOCK_SCREEN_WIDTH / 2, SHERLOCK_SCREEN_HEIGHT / 2)); // Load the data for the map _iconImages = new ImageFile("mapicons.vgs"); loadData(); // Load the palette Common::SeekableReadStream *stream = res.load("map.pal"); stream->read(screen._cMap, PALETTE_SIZE); screen.translatePalette(screen._cMap); delete stream; // Load the map image and draw it to the back buffer ImageFile *map = new ImageFile("map.vgs"); screen._backBuffer1.create(SHERLOCK_SCREEN_WIDTH * 2, SHERLOCK_SCREEN_HEIGHT * 2); screen._backBuffer1.blitFrom((*map)[0], Common::Point(0, 0)); delete map; screen.clear(); screen.setPalette(screen._cMap); drawMapIcons(); // Copy the map drawn in the back buffer to the secondary back buffer screen._backBuffer2.create(SHERLOCK_SCREEN_WIDTH * 2, SHERLOCK_SCREEN_HEIGHT * 2); screen._backBuffer2.blitFrom(screen._backBuffer1); // Display the built map to the screen screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); // Set initial scroll position _targetScroll = _bigPos; screen._currentScroll = Common::Point(-1, -1); do { // Allow for event processing and get the current mouse position events.pollEventsAndWait(); events.setButtonState(); Common::Point mousePos = events.screenMousePos(); if (debugger._showAllLocations == LOC_REFRESH) { drawMapIcons(); screen.slamArea(screen._currentScroll.x, screen._currentScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_WIDTH); } checkMapNames(true); if (mousePos.x < (SHERLOCK_SCREEN_WIDTH / 6)) _targetScroll.x -= 2 * SCROLL_SPEED * (SHERLOCK_SCREEN_WIDTH / 6 - mousePos.x) / (SHERLOCK_SCREEN_WIDTH / 6); if (mousePos.x > (SHERLOCK_SCREEN_WIDTH * 5 / 6)) _targetScroll.x += 2 * SCROLL_SPEED * (mousePos.x - (SHERLOCK_SCREEN_WIDTH * 5 / 6)) / (SHERLOCK_SCREEN_WIDTH / 6); if (mousePos.y < (SHERLOCK_SCREEN_HEIGHT / 6)) _targetScroll.y -= 2 * SCROLL_SPEED * (SHERLOCK_SCREEN_HEIGHT / 6 - mousePos.y) / (SHERLOCK_SCREEN_HEIGHT / 6); if (mousePos.y > (SHERLOCK_SCREEN_HEIGHT * 5 / 6)) _targetScroll.y += 2 * SCROLL_SPEED * (mousePos.y - SHERLOCK_SCREEN_HEIGHT * 5 / 6) / (SHERLOCK_SCREEN_HEIGHT / 6); if (_targetScroll.x < 0) _targetScroll.x = 0; if ((_targetScroll.x + SHERLOCK_SCREEN_WIDTH) > screen._backBuffer1.w()) _targetScroll.x = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH; if (_targetScroll.y < 0) _targetScroll.y = 0; if ((_targetScroll.y + SHERLOCK_SCREEN_HEIGHT) > screen._backBuffer1.h()) _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT; // Check the keyboard if (events.kbHit()) { Common::KeyState keyState = events.getKey(); switch (keyState.keycode) { case Common::KEYCODE_HOME: case Common::KEYCODE_KP7: _targetScroll.x = 0; _targetScroll.y = 0; break; case Common::KEYCODE_END: case Common::KEYCODE_KP1: _targetScroll.x = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH; _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT; break; case Common::KEYCODE_PAGEUP: case Common::KEYCODE_KP9: _targetScroll.y -= SHERLOCK_SCREEN_HEIGHT; if (_targetScroll.y < 0) _targetScroll.y = 0; break; case Common::KEYCODE_PAGEDOWN: case Common::KEYCODE_KP3: _targetScroll.y += SHERLOCK_SCREEN_HEIGHT; if (_targetScroll.y > (screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT)) _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT; break; case Common::KEYCODE_SPACE: events._pressed = false; events._oldButtons = 0; events._released = true; break; default: break; } } // Handle any scrolling of the map if (screen._currentScroll != _targetScroll) { // If there is a Text description being displayed, restore the area under it _mapTooltip.erase(); screen._currentScroll = _targetScroll; checkMapNames(false); screen.slamArea(_targetScroll.x, _targetScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } // Handling if a location has been clicked on if (events._released && _bgFound != -1) { // If there is a Text description being displayed, restore the area under it _mapTooltip.erase(); // Save the current scroll position on the map _bigPos = screen._currentScroll; showCloseUp(_bgFound); result = _bgFound + 1; } } while (!result && !_vm->shouldQuit()); music.stopMusic(); events.clearEvents(); _mapTooltip.banishWindow(); // Reset the back buffers back to standard size screen._backBuffer1.create(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); screen._backBuffer2.create(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); return result; }
void TXB::readHeader(Common::SeekableReadStream &txb, bool &needDeSwizzle) { // Number of bytes for the pixel data in one full image uint32 dataSize = txb.readUint32LE(); _dataSize = dataSize; txb.skip(4); // Some float // Image dimensions uint32 width = txb.readUint16LE(); uint32 height = txb.readUint16LE(); // How's the pixel data encoded? byte encoding = txb.readByte(); // Number of mip maps in the image byte mipMapCount = txb.readByte(); txb.skip(2); // Unknown (Always 0x0101 on 0x0A and 0x0C types, 0x0100 on 0x09?) txb.skip(4); // Some float txb.skip(108); // Reserved needDeSwizzle = false; uint32 minDataSize, mipMapSize; if (encoding == kEncodingBGRA) { // Raw BGRA needDeSwizzle = true; _compressed = false; _hasAlpha = true; _format = kPixelFormatBGRA; _formatRaw = kPixelFormatRGBA8; _dataType = kPixelDataType8; minDataSize = 4; mipMapSize = width * height * 4; } else if (encoding == kEncodingDXT1) { // S3TC DXT1 _compressed = true; _hasAlpha = false; _format = kPixelFormatBGR; _formatRaw = kPixelFormatDXT1; _dataType = kPixelDataType8; minDataSize = 8; mipMapSize = width * height / 2; } else if (encoding == kEncodingDXT5) { // S3TC DXT5 _compressed = true; _hasAlpha = true; _format = kPixelFormatBGRA; _formatRaw = kPixelFormatDXT5; _dataType = kPixelDataType8; minDataSize = 16; mipMapSize = width * height; } else if (encoding == 0x09) // TODO: This seems to be some compression with 8bit per pixel. No min // data size; 2*2 and 1*1 mipmaps seem to be just that big. // Image data doesn't seem to be simple grayscale, paletted, // RGB2222 or RGB332 data either. throw Common::Exception("Unsupported TXB encoding 0x09"); else throw Common::Exception("Unknown TXB encoding 0x%02X (%dx%d, %d, %d)", encoding, width, height, mipMapCount, dataSize); _mipMaps.reserve(mipMapCount); for (uint32 i = 0; i < mipMapCount; i++) { MipMap *mipMap = new MipMap; mipMap->width = MAX<uint32>(width, 1); mipMap->height = MAX<uint32>(height, 1); if (((width < 4) || (height < 4)) && (width != height)) // Invalid mipmap dimensions break; mipMap->size = MAX<uint32>(mipMapSize, minDataSize); mipMap->data = 0; if (dataSize < mipMap->size) { // Wouldn't fit delete mipMap; break; } dataSize -= mipMap->size; _mipMaps.push_back(mipMap); width >>= 1; height >>= 1; mipMapSize >>= 2; if ((width < 1) && (height < 1)) break; } }
bool Animation::loadStream(Common::SeekableReadStream &stream) { stream.skip(2); // skip not used x and y coord diff _loopCount = stream.readUint16LE(); _phaseCount = stream.readUint16LE(); stream.skip(2); // skip _frameCount here _baseX = stream.readUint16LE(); _baseY = stream.readUint16LE(); uint32 phaseTableOffset = stream.readUint32LE(); uint32 tableOfFrameOffsets = stream.pos(); stream.seek(phaseTableOffset); Phase tempPhase; _frameCount = 0; for (int phase = 0; phase < _phaseCount; phase++) { tempPhase._phaseOffsetX = stream.readSint16LE(); tempPhase._phaseOffsetY = stream.readSint16LE(); tempPhase._phaseToFrameIndex = stream.readUint16LE(); if (tempPhase._phaseToFrameIndex > _frameCount) { _frameCount = tempPhase._phaseToFrameIndex; } _phaseList.push_back(tempPhase); stream.skip(2); } if (_phaseCount) { _frameCount++; } Frame tempFrame; for (int frame = 0; frame < _frameCount; frame++) { stream.seek(tableOfFrameOffsets + frame * 4); uint32 frameInfoOffset = stream.readUint32LE(); stream.seek(frameInfoOffset); uint16 frameWidth = stream.readUint16LE(); uint16 frameHeight = stream.readUint16LE(); uint32 frameDataPos = stream.pos(); uint32 frameDataOffset = stream.readUint32BE(); tempFrame._surface = new Graphics::Surface(); tempFrame._surface->create(frameWidth, frameHeight, Graphics::PixelFormat::createFormatCLUT8()); if (frameDataOffset == MKTAG('m', 'a', 's', 'm')) { tempFrame._isCompressed = true; tempFrame._dataSize = stream.readUint32LE(); tempFrame._compressedData = (byte *)malloc(tempFrame._dataSize); stream.read(tempFrame._compressedData, tempFrame._dataSize); } else { tempFrame._isCompressed = false; tempFrame._dataSize = 0; tempFrame._compressedData = nullptr; stream.seek(frameDataPos); for (uint16 i = 0; i < frameHeight; i++) { stream.read(tempFrame._surface->getBasePtr(0, i), frameWidth); } } _frameList.push_back(tempFrame); } return true; }
Common::Point GameModule::readPoint(Common::SeekableReadStream &s) { Common::Point p; p.x = s.readUint16LE(); p.y = s.readUint16LE(); return p; }
void GameModule::loadAnimations(Common::SeekableReadStream &s) { debug(0, "GameModule::loadAnimations()"); s.seek(0x168); _animationsCount = s.readUint32LE(); uint32 offs = s.readUint32LE(); _animations = new Animation[_animationsCount]; for (int i = 0; i < _animationsCount; ++i) { Animation &anim = _animations[i]; s.seek(offs + i * 20); anim.frameCount = s.readUint32LE(); uint32 frameSpriteIndicesOffs = s.readUint32LE(); uint32 frameTicksOffs = s.readUint32LE(); uint32 frameRects1Offs = s.readUint32LE(); uint32 frameRects2Offs = s.readUint32LE(); anim.frameSpriteIndices = new int[anim.frameCount]; s.seek(frameSpriteIndicesOffs); for (int j = 0; j < anim.frameCount; ++j) anim.frameSpriteIndices[j] = s.readUint32LE(); anim.frameTicks = new int16[anim.frameCount]; s.seek(frameTicksOffs); for (int j = 0; j < anim.frameCount; ++j) anim.frameTicks[j] = s.readUint16LE(); anim.frameRects1 = new Common::Rect[anim.frameCount]; s.seek(frameRects1Offs); for (int j = 0; j < anim.frameCount; ++j) anim.frameRects1[j] = readRect(s); anim.frameRects2 = new Common::Rect[anim.frameCount]; s.seek(frameRects2Offs); for (int j = 0; j < anim.frameCount; ++j) anim.frameRects2[j] = readRect(s); } }
void CUP_Player::handleRGBS(Common::SeekableReadStream &dataStream, uint32 dataSize) { dataStream.read(_paletteData, 256 * 3); _paletteChanged = true; }
/* Island Sections (Num Entries HQR - 3 / 6 = Total Sections available) 3 (0) - Objects layout 4 (1) - Objects data 5 (2) - Quads (2 triangles) 6 (3) - Texture UV mapping 7 (4) - Height Maps 8 (5) - Intensity */ void Island::loadIslandSection(int sectionIdx, int entryIdx) { // 7 (4) - Height Maps int16 heightmap[65][65]; Common::SeekableReadStream *stream = _ile->createReadStreamForIndex(entryIdx + 4); _sectionsLayout = new byte[256]; stream->read(heightmap, 65*65); delete stream; // 6 (3) - Texture UV mapping GroundTextureInfo *textureInfo; stream = _ile->createReadStreamForIndex(entryIdx + 3); textureInfo = new GroundTextureInfo[stream->size() / 12]; stream->read(textureInfo, 65*65); delete stream; // 8 (5) - Intensity byte intensity[65][65]; stream = _ile->createReadStreamForIndex(entryIdx + 5); stream->read(intensity, 65*65); delete stream; // 5 (2) - Quads (2 triangles) GroundSquare squares[64][64]; stream = _ile->createReadStreamForIndex(entryIdx + 2); stream->read(squares, 64 * 64 * 8); delete stream; // Parse data int16 maxHeight = 0; Common::Array<float> vertices; vertices.reserve(9 * 64 * 64 * 4 * 2); Common::Array<uint16> faces; faces.reserve(6 * 64 * 64); // Vertex Count - In order of verts that make tris uint16 idx = 0; uint16 uvOrder[6] = {0, 1, 2, 2, 0, 1}; uint16 idxOrder1[6] = {0, 2, 3, 0, 3, 1}; uint16 idxOrder2[6] = {0, 2, 1, 1, 2, 3}; // For Every QUAD for (int32 x = 0; x < 64; ++x) { for (int32 y = 0; y < 64; ++y) { // Pass the pointer from the quad database to this quad (2 triangles passed) GroundTriangle *tri = squares[x][y].triangle; // Orientation uint16 *idxOrder = (tri[0].orientation == 0) ? idxOrder1 : idxOrder2; // For both tris in this quad... for (int32 t = 0; t < 2; ++t) { // Data Usage for this Tri int mdMax = 0; if (tri[t].useColor) mdMax++; if (tri[t].useTexture) mdMax++; // For all the data usage in this tri for (int32 md = 0; md < mdMax; ++md) { // For each vertex, offset by triangle num in quad for (int32 i = 3 * t; i < (3 + 3 * t); ++i) { int32 xi = x + idxOrder[i] / 2; int32 yi = y + idxOrder[i] % 2; // Vertex position vertices.push_back(((float)(xi) - 32) / 0x20); vertices.push_back(((float)(heightmap[xi][yi])) / 0x4000); vertices.push_back(((float)(64 - yi) - 32) / 0x20); if (heightmap[xi][yi] > maxHeight) maxHeight = heightmap[xi][yi]; // Vertex color and UV if (tri[t].useTexture && (mdMax < 2 || md == 1)) { float intens = intensity[xi][yi] / 16.0f + 0.3; if (intens > 1.0) intens = 1.0; vertices.push_back(intens); vertices.push_back(intens); vertices.push_back(intens); vertices.push_back(1.0); vertices.push_back((textureInfo[tri[t].textureIndex].uv[uvOrder[i]].u / 65535.0f) * 0.5); vertices.push_back(textureInfo[tri[t].textureIndex].uv[uvOrder[i]].v / 65535.0f); } else if (mdMax < 2 || md == 0) { byte colorIdx = (tri[t].textureBank * 16) + intensity[xi][yi]; // TODO get palette RGB components for colorIdx float r = 0; float g = 0; float b = 0; vertices.push_back(r); vertices.push_back(g); vertices.push_back(b); vertices.push_back(1.0); vertices.push_back(0.75f); vertices.push_back(0.5f); } } /* Index */ faces.push_back(idx); faces.push_back(idx + 1); faces.push_back(idx + 2); idx += 3; } } } } delete [] textureInfo; }
void CUP_Player::handleHEAD(Common::SeekableReadStream &dataStream, uint32 dataSize) { _playbackRate = dataStream.readUint16LE(); _width = dataStream.readUint16LE(); _height = dataStream.readUint16LE(); }
void ComposerEngine::loadLibrary(uint id) { if (getGameType() == GType_ComposerV1 && !_libraries.empty()) { // kill the previous page, starting with any scripts running on it for (Common::List<OldScript *>::iterator i = _oldScripts.begin(); i != _oldScripts.end(); i++) delete *i; _oldScripts.clear(); Library *library = &_libraries.front(); unloadLibrary(library->_id); } Common::String filename; if (getGameType() == GType_ComposerV1) { if (!id || _bookGroup.empty()) filename = getStringFromConfig("Common", "StartPage"); else filename = getStringFromConfig(_bookGroup, Common::String::format("%d", id)); filename = mangleFilename(filename); // bookGroup is the basename of the path. // TODO: tidy this up. _bookGroup.clear(); for (uint i = 0; i < filename.size(); i++) { if (filename[i] == '~' || filename[i] == '/' || filename[i] == ':') continue; for (uint j = 0; j < filename.size(); j++) { if (filename[j] == '/') { _bookGroup.clear(); continue; } if (filename[j] == '.') break; _bookGroup += filename[j]; } break; } } else { if (!id) id = atoi(getStringFromConfig("Common", "StartUp").c_str()); filename = getFilename("Libs", id); } Library library; library._id = id; library._archive = new ComposerArchive(); if (!library._archive->openFile(filename)) error("failed to open '%s'", filename.c_str()); _libraries.push_front(library); Library &newLib = _libraries.front(); Common::Array<uint16> buttonResources = library._archive->getResourceIDList(ID_BUTN); for (uint i = 0; i < buttonResources.size(); i++) { uint16 buttonId = buttonResources[i]; Common::SeekableReadStream *stream = library._archive->getResource(ID_BUTN, buttonId); Button button(stream, buttonId, getGameType()); bool inserted = false; for (Common::List<Button>::iterator b = newLib._buttons.begin(); b != newLib._buttons.end(); b++) { if (button._zorder < b->_zorder) continue; newLib._buttons.insert(b, button); inserted = true; break; } if (!inserted) newLib._buttons.push_back(button); } Common::Array<uint16> ambientResources = library._archive->getResourceIDList(ID_AMBI); for (uint i = 0; i < ambientResources.size(); i++) { Common::SeekableReadStream *stream = library._archive->getResource(ID_AMBI, ambientResources[i]); Button button(stream); newLib._buttons.insert(newLib._buttons.begin(), button); } Common::Array<uint16> accelResources = library._archive->getResourceIDList(ID_ACEL); for (uint i = 0; i < accelResources.size(); i++) { Common::SeekableReadStream *stream = library._archive->getResource(ID_ACEL, accelResources[i]); KeyboardHandler handler; handler.keyId = stream->readUint16LE(); handler.modifierId = stream->readUint16LE(); handler.scriptId = stream->readUint16LE(); newLib._keyboardHandlers.push_back(handler); } Common::Array<uint16> randResources = library._archive->getResourceIDList(ID_RAND); for (uint i = 0; i < randResources.size(); i++) { Common::SeekableReadStream *stream = library._archive->getResource(ID_RAND, randResources[i]); Common::Array<RandomEvent> &events = _randomEvents[randResources[i]]; uint16 count = stream->readUint16LE(); for (uint j = 0; j < count; j++) { RandomEvent random; random.scriptId = stream->readUint16LE(); random.weight = stream->readUint16LE(); events.push_back(random); } delete stream; } // add background sprite, if it exists if (hasResource(ID_BMAP, 1000)) setBackground(1000); // TODO: better CTBL logic loadCTBL(1000, 100); // Run the startup script. runScript(1000, 0, 0, 0); _mouseEnabled = true; onMouseMove(_lastMousePos); runEvent(kEventLoad, id, 0, 0); }
void DrasculaEngine::screenSaver() { int xr, yr; byte *copia, *ghost; float coeff = 0, coeff2 = 0; int count = 0; int count2 = 0; int tempLine[320]; int tempRow[200]; hideCursor(); clearRoom(); loadPic("sv.alg", bgSurface, HALF_PAL); // inicio_ghost(); copia = (byte *)malloc(64000); ghost = (byte *)malloc(65536); // carga_ghost(); Common::SeekableReadStream *stream = _archives.open("ghost.drv"); if (!stream) error("Cannot open file ghost.drv"); stream->read(ghost, 65536); delete stream; updateEvents(); xr = mouseX; yr = mouseY; for (;;) { // efecto(bgSurface); memcpy(copia, bgSurface, 64000); coeff += 0.1f; coeff2 = coeff; if (++count > 319) count = 0; for (int i = 0; i < 320; i++) { tempLine[i] = (int)(sin(coeff2) * 16); coeff2 += 0.02f; tempLine[i] = checkWrapY(tempLine[i]); } coeff2 = coeff; for (int i = 0; i < 200; i++) { tempRow[i] = (int)(sin(coeff2) * 16); coeff2 += 0.02f; tempRow[i] = checkWrapX(tempRow[i]); } if (++count2 > 199) count2 = 0; int x1_, y1_, off1, off2; byte *screenBuffer = (byte *)_system->lockScreen()->pixels; for (int i = 0; i < 200; i++) { for (int j = 0; j < 320; j++) { x1_ = j + tempRow[i]; x1_ = checkWrapX(x1_); y1_ = i + count2; y1_ = checkWrapY(y1_); off1 = 320 * y1_ + x1_; x1_ = j + count; x1_ = checkWrapX(x1_); y1_ = i + tempLine[j]; y1_ = checkWrapY(y1_); off2 = 320 * y1_ + x1_; screenBuffer[320 * i + j] = ghost[bgSurface[off2] + (copia[off1] << 8)]; } } _system->unlockScreen(); _system->updateScreen(); _system->delayMillis(20); // end of efecto() updateEvents(); if (rightMouseButton == 1 || leftMouseButton == 1) break; if (mouseX != xr) break; if (mouseY != yr) break; } // fin_ghost(); free(copia); free(ghost); loadPic(roomNumber, bgSurface, HALF_PAL); showCursor(); }
/** * Savegame format detector * @param fHandle Savefile to check * @return Savegame format on success, ANIMSIZE_UNKNOWN on failure * * This function seeks through the savefile and tries to determine the * savegame format it uses. There's a miniscule chance that the detection * algorithm could get confused and think that the file uses both the older * and the newer format but that is such a remote possibility that I wouldn't * worry about it at all. * * Also detects the temporary Operation Stealth savegame format now. */ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle) { const uint32 prevStreamPos = fHandle.pos(); // First check for the temporary Operation Stealth savegame format. fHandle.seek(0); ChunkHeader hdr; loadChunkHeader(fHandle, hdr); fHandle.seek(prevStreamPos); if (hdr.id == TEMP_OS_FORMAT_ID) { return TEMP_OS_FORMAT; } // Ok, so the savegame isn't using the temporary Operation Stealth savegame format. // Let's check for the plain Future Wars savegame format and its different versions then. // The animDataTable begins at savefile position 0x2315. // Each animDataTable entry takes 23 bytes in older saves (Revisions 21772-31443) // and 30 bytes in the save format after that (Revision 31444 and onwards). // There are 255 entries in the animDataTable in both of the savefile formats. static const uint animDataTableStart = 0x2315; static const uint animEntriesCount = 255; static const uint oldAnimEntrySize = 23; static const uint newAnimEntrySize = 30; static const uint animEntrySizeChoices[] = {oldAnimEntrySize, newAnimEntrySize}; Common::Array<uint> animEntrySizeMatches; // Try to walk through the savefile using different animDataTable entry sizes // and make a list of all the successful entry sizes. for (uint i = 0; i < ARRAYSIZE(animEntrySizeChoices); i++) { // 206 = 2 * 50 * 2 + 2 * 3 (Size of global and object script entries) // 20 = 4 * 2 + 2 * 6 (Size of overlay and background incrust entries) static const uint sizeofScreenParams = 2 * 6; static const uint globalScriptEntrySize = 206; static const uint objectScriptEntrySize = 206; static const uint overlayEntrySize = 20; static const uint bgIncrustEntrySize = 20; static const uint chainEntrySizes[] = { globalScriptEntrySize, objectScriptEntrySize, overlayEntrySize, bgIncrustEntrySize }; uint animEntrySize = animEntrySizeChoices[i]; // Jump over the animDataTable entries and the screen parameters int32 newPos = animDataTableStart + animEntrySize * animEntriesCount + sizeofScreenParams; // Check that there's data left after the point we're going to jump to if (newPos >= fHandle.size()) { continue; } fHandle.seek(newPos); // Jump over the remaining items in the savegame file // (i.e. the global scripts, object scripts, overlays and background incrusts). bool chainWalkSuccess = true; for (uint chainIndex = 0; chainIndex < ARRAYSIZE(chainEntrySizes); chainIndex++) { // Read entry count and jump over the entries int entryCount = fHandle.readSint16BE(); newPos = fHandle.pos() + chainEntrySizes[chainIndex] * entryCount; // Check that we didn't go past the end of file. // Note that getting exactly to the end of file is acceptable. if (newPos > fHandle.size()) { chainWalkSuccess = false; break; } fHandle.seek(newPos); } // If we could walk the chain successfully and // got exactly to the end of file then we've got a match. if (chainWalkSuccess && fHandle.pos() == fHandle.size()) { // We found a match, let's save it animEntrySizeMatches.push_back(animEntrySize); } } // Check that we got only one entry size match. // If we didn't, then return an error. enum CineSaveGameFormat result = ANIMSIZE_UNKNOWN; if (animEntrySizeMatches.size() == 1) { const uint animEntrySize = animEntrySizeMatches[0]; assert(animEntrySize == oldAnimEntrySize || animEntrySize == newAnimEntrySize); if (animEntrySize == oldAnimEntrySize) { result = ANIMSIZE_23; } else { // animEntrySize == newAnimEntrySize // Check data and mask pointers in all of the animDataTable entries // to see whether we've got the version with the broken data and mask pointers or not. // In the broken format all data and mask pointers were always zero. static const uint relativeDataPos = 2 * 4; bool pointersIntact = false; for (uint i = 0; i < animEntriesCount; i++) { fHandle.seek(animDataTableStart + i * animEntrySize + relativeDataPos); uint32 data = fHandle.readUint32BE(); uint32 mask = fHandle.readUint32BE(); if ((data != 0) || (mask != 0)) { pointersIntact = true; break; } } result = (pointersIntact ? ANIMSIZE_30_PTRS_INTACT : ANIMSIZE_30_PTRS_BROKEN); } } else if (animEntrySizeMatches.size() > 1) { warning("Savegame format detector got confused by input data. Detecting savegame to be using an unknown format"); } else { // animEtrySizeMatches.size() == 0 debug(3, "Savegame format detector was unable to detect savegame's format"); } fHandle.seek(prevStreamPos); return result; }
void GameModule::loadActions(Common::SeekableReadStream &s) { debug(0, "GameModule::loadActions()"); s.seek(0x180); _actionsCount = s.readUint32LE(); uint32 offs = s.readUint32LE(); _actions = new Action[_actionsCount]; for (int i = 0; i < _actionsCount; ++i) { s.seek(offs + i * 72); debug(0, "Action(%d) offs: %08X", i, offs + i * 72); _actions[i].conditions = readConditions(s); for (int j = 0; j < 8; ++j) { _actions[i].results.actionResults[j].kind = s.readByte(); _actions[i].results.actionResults[j].value1 = s.readByte(); _actions[i].results.actionResults[j].value2 = s.readUint16LE(); } const int actionListCount = s.readUint32LE(); const uint32 actionListOffs = s.readUint32LE(); s.seek(actionListOffs); for (int j = 0; j < actionListCount; ++j) { ActionCommand actionCommand; actionCommand.cmd = s.readUint16LE(); actionCommand.sceneObjectIndex = s.readUint16LE(); actionCommand.timeStamp = s.readUint32LE(); actionCommand.walkDest = readPoint(s); actionCommand.param = s.readUint32LE(); _actions[i].actionCommands.push_back(actionCommand); } } }
/** * Load animDataTable from save * @param fHandle Savefile open for reading * @param saveGameFormat The used savegame format * @todo Add Operation Stealth savefile support * * Unlike the old code, this one actually rebuilds the table one frame * at a time. */ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat) { int16 foundFileIdx; char *animName, part[256], name[10]; strcpy(part, currentPartName); // We only support these variations of the savegame format at the moment. assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT); const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30); const int fileStartPos = fHandle.pos(); for(int resourceIndex=0; resourceIndex<NUM_MAX_ANIMDATA; resourceIndex++) { // Seek to the start of the current animation's entry fHandle.seek(fileStartPos + resourceIndex * entrySize); // Read in the current animation entry fHandle.readUint16BE(); // width fHandle.readUint16BE(); fHandle.readUint16BE(); // bpp fHandle.readUint16BE(); // height bool validPtr = false; // Handle variables only present in animation entries of size 30 if (entrySize == 30) { validPtr = (fHandle.readUint32BE() != 0); // Read data pointer fHandle.readUint32BE(); // Discard mask pointer } foundFileIdx = fHandle.readSint16BE(); int16 frameIndex = fHandle.readSint16BE(); // frame fHandle.read(name, 10); // Handle variables only present in animation entries of size 23 if (entrySize == 23) { validPtr = (fHandle.readByte() != 0); } // Don't try to load invalid entries. if (foundFileIdx < 0 || !validPtr) { //resourceIndex++; // Jump over the invalid entry continue; } // Alright, the animation entry looks to be valid so let's start handling it... if (strcmp(currentPartName, name) != 0) { closePart(); loadPart(name); } animName = g_cine->_partBuffer[foundFileIdx].partName; loadRelatedPalette(animName); // Is this for Future Wars only? loadResource(animName, resourceIndex, frameIndex); } loadPart(part); // Make sure we jump over all the animation entries fHandle.seek(fileStartPos + NUM_MAX_ANIMDATA * entrySize); }
bool loadCommandVariables(Common::SeekableReadStream &in) { for (int i = 0; i < 4; i++) { commandVar3[i] = in.readUint16BE(); } return !(in.eos() || in.err()); }
InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) : Control(engine, key, CONTROL_INPUT), _nextTabstop(0), _focused(false), _textChanged(false), _cursorOffset(0), _enterPressed(false), _readOnly(false), _txtWidth(0), _animation(NULL) { // Loop until we find the closing brace Common::String line = stream.readLine(); trimCommentsAndWhiteSpace(&line); Common::String param; Common::String values; getParams(line, param, values); while (!stream.eos() && !line.contains('}')) { if (param.matchString("rectangle", true)) { int x1; int y1; int x2; int y2; sscanf(values.c_str(), "%d %d %d %d", &x1, &y1, &x2, &y2); _textRectangle = Common::Rect(x1, y1, x2, y2); } else if (param.matchString("aux_hotspot", true)) { int x1; int y1; int x2; int y2; sscanf(values.c_str(), "%d %d %d %d", &x1, &y1, &x2, &y2); _headerRectangle = Common::Rect(x1, y1, x2, y2); } else if (param.matchString("string_init", true)) { uint fontFormatNumber; sscanf(values.c_str(), "%u", &fontFormatNumber); _stringInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber)); } else if (param.matchString("chooser_init_string", true)) { uint fontFormatNumber; sscanf(values.c_str(), "%u", &fontFormatNumber); _stringChooserInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber)); } else if (param.matchString("next_tabstop", true)) { sscanf(values.c_str(), "%u", &_nextTabstop); } else if (param.matchString("cursor_dimensions", true)) { // Ignore, use the dimensions in the animation file } else if (param.matchString("cursor_animation_frames", true)) { // Ignore, use the frame count in the animation file } else if (param.matchString("cursor_animation", true)) { char fileName[25]; sscanf(values.c_str(), "%25s %*u", fileName); _animation = new MetaAnimation(fileName, _engine); _frame = -1; _frameDelay = 0; } else if (param.matchString("focus", true)) { _focused = true; _engine->getScriptManager()->setFocusControlKey(_key); } else if (param.matchString("venus_id", true)) { _venusId = atoi(values.c_str()); } line = stream.readLine(); trimCommentsAndWhiteSpace(&line); getParams(line, param, values); } }
bool loadSeqList(Common::SeekableReadStream &in) { uint size = in.readUint16BE(); SeqListElement tmp; for (uint i = 0; i < size; i++) { tmp.var4 = in.readSint16BE(); tmp.objIdx = in.readUint16BE(); tmp.var8 = in.readSint16BE(); tmp.frame = in.readSint16BE(); tmp.varC = in.readSint16BE(); tmp.varE = in.readSint16BE(); tmp.var10 = in.readSint16BE(); tmp.var12 = in.readSint16BE(); tmp.var14 = in.readSint16BE(); tmp.var16 = in.readSint16BE(); tmp.var18 = in.readSint16BE(); tmp.var1A = in.readSint16BE(); tmp.var1C = in.readSint16BE(); tmp.var1E = in.readSint16BE(); g_cine->_seqList.push_back(tmp); } return !(in.eos() || in.err()); }
void Font::setFontM4(const char *filename) { Common::SeekableReadStream *fontFile = _vm->res()->openFile(filename); if (fontFile->readUint32LE() != MKTAG('F','O','N','T')) { debugCN(kDebugGraphics, "Font::Font: FONT tag expected\n"); return; } _maxHeight = fontFile->readByte(); _maxWidth = fontFile->readByte(); uint32 fontSize = fontFile->readUint32LE(); //debugCN(kDebugGraphics, "Font::Font: _maxWidth = %d, _maxHeight = %d, fontSize = %d\n", _maxWidth, _maxHeight, fontSize); if (fontFile->readUint32LE() != MKTAG('W','I','D','T')) { debugCN(kDebugGraphics, "Font::Font: WIDT tag expected\n"); return; } _charWidths = new uint8[256]; fontFile->read(_charWidths, 256); if (fontFile->readUint32LE() != MKTAG('O','F','F','S')) { debugCN(kDebugGraphics, "Font::Font: OFFS tag expected\n"); return; } _charOffs = new uint16[256]; for (int i = 0; i < 256; i++) _charOffs[i] = fontFile->readUint16LE(); if (fontFile->readUint32LE() != MKTAG('P','I','X','S')) { debugCN(kDebugGraphics, "Font::Font: PIXS tag expected\n"); return; } _charData = new uint8[fontSize]; fontFile->read(_charData, fontSize); _vm->res()->toss(filename); }
bool loadZoneQuery(Common::SeekableReadStream &in) { for (int i = 0; i < 16; i++) { g_cine->_zoneQuery[i] = in.readUint16BE(); } return !(in.eos() || in.err()); }
void TattooMap::loadData() { Resources &res = *_vm->_res; char c; Common::SeekableReadStream *stream = res.load("map.txt"); _data.resize(100); for (uint idx = 0; idx < _data.size(); ++idx) _data[idx].clear(); do { // Find the start of the number do { c = stream->readByte(); if (stream->pos() >= stream->size()) return; } while (c < '0' || c > '9'); // Get the scene number Common::String locStr; locStr += c; while ((c = stream->readByte()) != '.') locStr += c; MapEntry &mapEntry = _data[atoi(locStr.c_str()) - 1]; // Get the location name while (stream->readByte() != '"') ; while ((c = stream->readByte()) != '"') mapEntry._description += c; // Find the ( specifying the (X,Y) position of the Icon while (stream->readByte() != '(') ; // Get the X Position of the icon Common::String numStr; while ((c = stream->readByte()) != ',') numStr += c; mapEntry.x = atoi(numStr.c_str()); // Get the Y position of the icon numStr = ""; while ((c = stream->readByte()) != ')') numStr += c; mapEntry.y = atoi(numStr.c_str()); // Find and get the location's icon number while (stream->readByte() != '#') ; Common::String iconStr; while (stream->pos() < stream->size() && (c = stream->readByte()) != '\r') iconStr += c; mapEntry._iconNum = atoi(iconStr.c_str()) - 1; } while (stream->pos() < stream->size()); delete stream; }
bool loadChunkHeader(Common::SeekableReadStream &in, ChunkHeader &header) { header.id = in.readUint32BE(); header.version = in.readUint32BE(); header.size = in.readUint32BE(); return !(in.eos() || in.err()); }
void TitanicEngine::setRoomNames() { Common::SeekableReadStream *r = g_vm->_filesManager->getResource("TEXT/ROOM_NAMES"); while (r->pos() < r->size()) _roomNames.push_back(readStringFromStream(r)); delete r; }
bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { char musicName[13]; char bgNames[8][13]; // First check the temporary Operation Stealth savegame format header. ChunkHeader hdr; loadChunkHeader(in, hdr); if (hdr.id != TEMP_OS_FORMAT_ID) { warning("loadTempSaveOS: File has incorrect identifier. Not loading savegame"); return false; } else if (hdr.version > CURRENT_OS_SAVE_VER) { warning("loadTempSaveOS: Detected newer format version. Not loading savegame"); return false; } else if ((int)hdr.version < (int)CURRENT_OS_SAVE_VER) { warning("loadTempSaveOS: Detected older format version. Trying to load nonetheless. Things may break"); } else { // hdr.id == TEMP_OS_FORMAT_ID && hdr.version == CURRENT_OS_SAVE_VER debug(3, "loadTempSaveOS: Found correct header (Both the identifier and version number match)."); } // There shouldn't be any data in the header's chunk currently so it's an error if there is. if (hdr.size > 0) { warning("loadTempSaveOS: Format header's chunk seems to contain data so format is incorrect. Not loading savegame"); return false; } // Ok, so we've got a correct header for a temporary Operation Stealth savegame. // Let's start loading the plain savegame data then. currentDisk = in.readUint16BE(); in.read(currentPartName, 13); in.read(currentPrcName, 13); in.read(currentRelName, 13); in.read(currentMsgName, 13); // Load the 8 background names. for (uint i = 0; i < 8; i++) { in.read(bgNames[i], 13); } in.read(currentCtName, 13); // Moved the loading of current procedure, relation, // backgrounds and Ct here because if they were at the // end of this function then the global scripts loading // made an array out of bounds access. In the original // game's disassembly these aren't here but at the end. // The difference is probably in how we handle loading // the global scripts and some other things (i.e. the // loading routines aren't exactly the same and subtle // semantic differences result in having to do things // in a different order). { // Not sure if this is needed with Operation Stealth... checkDataDisk(currentDisk); if (strlen(currentPrcName)) { loadPrc(currentPrcName); } if (strlen(currentRelName)) { loadRel(currentRelName); } // Load first background (Uses loadBg) if (strlen(bgNames[0])) { loadBg(bgNames[0]); } // Add backgrounds 1-7 (Uses addBackground) for (int i = 1; i < 8; i++) { if (strlen(bgNames[i])) { addBackground(bgNames[i], i); } } if (strlen(currentCtName)) { loadCtOS(currentCtName); } } loadObjectTable(in); renderer->restorePalette(in, hdr.version); g_cine->_globalVars.load(in, NUM_MAX_VAR); loadZoneData(in); loadCommandVariables(in); char tempCommandBuffer[kMaxCommandBufferSize]; in.read(tempCommandBuffer, kMaxCommandBufferSize); g_cine->_commandBuffer = tempCommandBuffer; renderer->setCommand(g_cine->_commandBuffer); loadZoneQuery(in); // TODO: Use the loaded string (Current music name (String, 13 bytes)). in.read(musicName, 13); // TODO: Use the loaded value (Is music loaded? (Uint16BE, Boolean)). in.readUint16BE(); // TODO: Use the loaded value (Is music playing? (Uint16BE, Boolean)). in.readUint16BE(); renderer->_cmdY = in.readUint16BE(); in.readUint16BE(); // Some unknown variable that seems to always be zero allowPlayerInput = in.readUint16BE(); playerCommand = in.readUint16BE(); commandVar1 = in.readUint16BE(); isDrawCommandEnabled = in.readUint16BE(); var5 = in.readUint16BE(); var4 = in.readUint16BE(); var3 = in.readUint16BE(); var2 = in.readUint16BE(); commandVar2 = in.readUint16BE(); renderer->_messageBg = in.readUint16BE(); // TODO: Use the loaded value (adBgVar1 (Uint16BE)). in.readUint16BE(); currentAdditionalBgIdx = in.readSint16BE(); currentAdditionalBgIdx2 = in.readSint16BE(); // TODO: Check whether the scroll value really gets used correctly after this. // Note that the backgrounds are loaded only later than this value is set. renderer->setScroll(in.readUint16BE()); // TODO: Use the loaded value (adBgVar0 (Uint16BE). Maybe this means bgVar0?). in.readUint16BE(); disableSystemMenu = in.readUint16BE(); // TODO: adBgVar1 = 1 here // Load the animDataTable entries in.readUint16BE(); // Entry count (255 in the PC version of Operation Stealth). in.readUint16BE(); // Entry size (36 in the PC version of Operation Stealth). loadResourcesFromSave(in, ANIMSIZE_30_PTRS_INTACT); loadScreenParams(in); loadGlobalScripts(in); loadObjectScripts(in); loadSeqList(in); loadOverlayList(in); loadBgIncrustFromSave(in); // Left this here instead of moving it earlier in this function with // the other current value loadings (e.g. loading of current procedure, // current backgrounds etc). Mostly emulating the way we've handled // Future Wars savegames and hoping that things work out. if (strlen(currentMsgName)) { loadMsg(currentMsgName); } // TODO: Add current music loading and playing here // TODO: Palette handling? if (in.pos() == in.size()) { debug(3, "loadTempSaveOS: Loaded the whole savefile."); } else { warning("loadTempSaveOS: Loaded the savefile but didn't exhaust it completely. Something was left over"); } return !(in.eos() || in.err()); }
// Additional information found from http://paulbourke.net/dataformats/tga/ // With some details from the link referenced in the header. bool TGADecoder::readData(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { // TrueColor if (imageType == TYPE_TRUECOLOR) { _surface.create(_surface.w, _surface.h, _format); if (pixelDepth == 16) { for (int i = 0; i < _surface.h; i++) { uint16 *dst; if (!_originTop) { dst = (uint16 *)_surface.getBasePtr(0, _surface.h - i - 1); } else { dst = (uint16 *)_surface.getBasePtr(0, i); } for (int j = 0; j < _surface.w; j++) { *dst++ = tga.readUint16LE(); } } } else if (pixelDepth == 32) { for (int i = 0; i < _surface.h; i++) { uint32 *dst; if (!_originTop) { dst = (uint32 *)_surface.getBasePtr(0, _surface.h - i - 1); } else { dst = (uint32 *)_surface.getBasePtr(0, i); } for (int j = 0; j < _surface.w; j++) { *dst++ = tga.readUint32LE(); } } } else if (pixelDepth == 24) { for (int i = 0; i < _surface.h; i++) { byte *dst; if (!_originTop) { dst = (byte *)_surface.getBasePtr(0, _surface.h - i - 1); } else { dst = (byte *)_surface.getBasePtr(0, i); } for (int j = 0; j < _surface.w; j++) { byte r = tga.readByte(); byte g = tga.readByte(); byte b = tga.readByte(); #ifdef SCUMM_LITTLE_ENDIAN *dst++ = r; *dst++ = g; *dst++ = b; #else *dst++ = b; *dst++ = g; *dst++ = r; #endif } } } // Black/White } else if (imageType == TYPE_BW) { _surface.create(_surface.w, _surface.h, _format); byte *data = (byte *)_surface.getPixels(); uint32 count = _surface.w * _surface.h; while (count-- > 0) { byte g = tga.readByte(); *data++ = g; *data++ = g; *data++ = g; *data++ = g; } } return true; }
bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) { char bgName[13]; // At savefile position 0x0000: currentDisk = in.readUint16BE(); // At 0x0002: in.read(currentPartName, 13); // At 0x000F: in.read(currentDatName, 13); // At 0x001C: musicIsPlaying = in.readSint16BE(); // At 0x001E: in.read(currentPrcName, 13); // At 0x002B: in.read(currentRelName, 13); // At 0x0038: in.read(currentMsgName, 13); // At 0x0045: in.read(bgName, 13); // At 0x0052: in.read(currentCtName, 13); checkDataDisk(currentDisk); if (strlen(currentPartName)) { loadPart(currentPartName); } if (strlen(currentPrcName)) { loadPrc(currentPrcName); } if (strlen(currentRelName)) { loadRel(currentRelName); } if (strlen(bgName)) { loadBg(bgName); } if (strlen(currentCtName)) { loadCtFW(currentCtName); } // At 0x005F: loadObjectTable(in); // At 0x2043 (i.e. 0x005F + 2 * 2 + 255 * 32): renderer->restorePalette(in, 0); // At 0x2083 (i.e. 0x2043 + 16 * 2 * 2): g_cine->_globalVars.load(in, NUM_MAX_VAR); // At 0x2281 (i.e. 0x2083 + 255 * 2): loadZoneData(in); // At 0x22A1 (i.e. 0x2281 + 16 * 2): loadCommandVariables(in); // At 0x22A9 (i.e. 0x22A1 + 4 * 2): char tempCommandBuffer[kMaxCommandBufferSize]; in.read(tempCommandBuffer, kMaxCommandBufferSize); g_cine->_commandBuffer = tempCommandBuffer; renderer->setCommand(g_cine->_commandBuffer); // At 0x22F9 (i.e. 0x22A9 + 0x50): renderer->_cmdY = in.readUint16BE(); // At 0x22FB: bgVar0 = in.readUint16BE(); // At 0x22FD: allowPlayerInput = in.readUint16BE(); // At 0x22FF: playerCommand = in.readSint16BE(); // At 0x2301: commandVar1 = in.readSint16BE(); // At 0x2303: isDrawCommandEnabled = in.readUint16BE(); // At 0x2305: var5 = in.readUint16BE(); // At 0x2307: var4 = in.readUint16BE(); // At 0x2309: var3 = in.readUint16BE(); // At 0x230B: var2 = in.readUint16BE(); // At 0x230D: commandVar2 = in.readSint16BE(); // At 0x230F: renderer->_messageBg = in.readUint16BE(); // At 0x2311: in.readUint16BE(); // At 0x2313: in.readUint16BE(); // At 0x2315: loadResourcesFromSave(in, saveGameFormat); loadScreenParams(in); loadGlobalScripts(in); loadObjectScripts(in); loadOverlayList(in); loadBgIncrustFromSave(in); if (strlen(currentMsgName)) { loadMsg(currentMsgName); } if (strlen(currentDatName)) { g_sound->loadMusic(currentDatName); if (musicIsPlaying) { g_sound->playMusic(); } } return !(in.eos() || in.err()); }
bool TGADecoder::readHeader(Common::SeekableReadStream &tga, byte &imageType, byte &pixelDepth) { if (!tga.seek(0)) { warning("Failed reading TGA-file"); return false; } // TGAs have an optional "id" string in the header uint32 idLength = tga.readByte(); // Number of colors in the color map / palette int hasColorMap = tga.readByte(); // Image type. See header for numeric constants imageType = tga.readByte(); switch (imageType) { case TYPE_CMAP: case TYPE_TRUECOLOR: case TYPE_BW: case TYPE_RLE_CMAP: case TYPE_RLE_TRUECOLOR: case TYPE_RLE_BW: break; default: warning("Unsupported image type: %d", imageType); return false; } // Color map specifications if (hasColorMap == 0) { tga.skip(5); } else { _colorMapOrigin = tga.readUint16LE(); _colorMapLength = tga.readUint16LE(); _colorMapEntryLength = tga.readByte(); } // Origin-defintions tga.skip(2 + 2); // Image dimensions _surface.w = tga.readUint16LE(); _surface.h = tga.readUint16LE(); // Bits per pixel pixelDepth = tga.readByte(); _surface.format.bytesPerPixel = pixelDepth / 8; // Image descriptor byte imgDesc = tga.readByte(); int attributeBits = imgDesc & 0x0F; assert((imgDesc & 0x10) == 0); _originTop = (imgDesc & 0x20); // Interleaving is not handled at this point //int interleave = (imgDesc & 0xC); if (imageType == TYPE_CMAP || imageType == TYPE_RLE_CMAP) { if (pixelDepth == 8) { _format = Graphics::PixelFormat::createFormatCLUT8(); } else { warning("Unsupported index-depth: %d", pixelDepth); return false; } } else if (imageType == TYPE_TRUECOLOR || imageType == TYPE_RLE_TRUECOLOR) { if (pixelDepth == 24) { _format = Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0); } else if (pixelDepth == 32) { // HACK: According to the spec, attributeBits should determine the amount // of alpha-bits, however, as the game files that use this decoder seems // to ignore that fact, we force the amount to 8 for 32bpp files for now. _format = Graphics::PixelFormat(4, 8, 8, 8, /* attributeBits */ 8, 16, 8, 0, 24); } else if (pixelDepth == 16) { // 16bpp TGA is ARGB1555 _format = Graphics::PixelFormat(2, 5, 5, 5, attributeBits, 10, 5, 0, 15); } else { warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth); return false; } } else if (imageType == TYPE_BW || imageType == TYPE_RLE_BW) { if (pixelDepth == 8) { _format = Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 0); } else { warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth); return false; } } else { warning("Unsupported image type: %d", imageType); return false; } // Skip the id string tga.skip(idLength); if (hasColorMap) { return readColorMap(tga, imageType, pixelDepth); } return true; }
bool WinCursor::readFromStream(Common::SeekableReadStream &stream) { clear(); _hotspotX = stream.readUint16LE(); _hotspotY = stream.readUint16LE(); // Check header size if (stream.readUint32LE() != 40) return false; // Check dimensions _width = stream.readUint32LE(); _height = stream.readUint32LE() / 2; if (_width & 3) { // Cursors should always be a power of 2 // Of course, it wouldn't be hard to handle but if we have no examples... warning("Non-divisible-by-4 width cursor found"); return false; } // Color planes if (stream.readUint16LE() != 1) return false; // Only 1bpp and 8bpp supported uint16 bitsPerPixel = stream.readUint16LE(); if (bitsPerPixel != 1 && bitsPerPixel != 8) return false; // Compression if (stream.readUint32LE() != 0) return false; // Image size + X resolution + Y resolution stream.skip(12); uint32 numColors = stream.readUint32LE(); // If the color count is 0, then it uses up the maximum amount if (numColors == 0) numColors = 1 << bitsPerPixel; // Reading the palette stream.seek(40 + 4); for (uint32 i = 0 ; i < numColors; i++) { _palette[i * 3 + 2] = stream.readByte(); _palette[i * 3 + 1] = stream.readByte(); _palette[i * 3 ] = stream.readByte(); stream.readByte(); } // Reading the bitmap data uint32 dataSize = stream.size() - stream.pos(); byte *initialSource = new byte[dataSize]; stream.read(initialSource, dataSize); // Parse the XOR map const byte *src = initialSource; _surface = new byte[_width * _height]; byte *dest = _surface + _width * (_height - 1); uint32 imagePitch = _width * bitsPerPixel / 8; for (uint32 i = 0; i < _height; i++) { byte *rowDest = dest; if (bitsPerPixel == 1) { // 1bpp for (uint16 j = 0; j < (_width / 8); j++) { byte p = src[j]; for (int k = 0; k < 8; k++, rowDest++, p <<= 1) { if ((p & 0x80) == 0x80) *rowDest = 1; else *rowDest = 0; } } } else { // 8bpp memcpy(rowDest, src, _width); } dest -= _width; src += imagePitch; } // Calculate our key color if (numColors < 256) { // If we're not using the maximum colors in a byte, we can fit it in _keyColor = numColors; } else { // HACK: Try to find a color that's not being used so it can become // our keycolor. It's quite impossible to fit 257 entries into 256... for (uint32 i = 0; i < 256; i++) { for (int j = 0; j < _width * _height; j++) { // TODO: Also check to see if the space is transparent if (_surface[j] == i) break; if (j == _width * _height - 1) { _keyColor = i; i = 256; break; } } } } // Now go through and apply the AND map to get the transparency uint32 andWidth = (_width + 7) / 8; src += andWidth * (_height - 1); for (uint32 y = 0; y < _height; y++) { for (uint32 x = 0; x < _width; x++) if (src[x / 8] & (1 << (7 - x % 8))) _surface[y * _width + x] = _keyColor; src -= andWidth; } delete[] initialSource; return true; }