diff --git a/graphics/wincursor.cpp b/graphics/wincursor.cpp index e5634a0fdca..15e7aba7718 100644 --- a/graphics/wincursor.cpp +++ b/graphics/wincursor.cpp @@ -31,7 +31,7 @@ namespace Graphics { /** A Windows cursor. */ class WinCursor : public Cursor { public: - WinCursor(); + WinCursor(uint16 hotspotX, uint16 hotspotY); ~WinCursor(); /** Return the cursor's width. */ @@ -56,6 +56,8 @@ public: bool readFromStream(Common::SeekableReadStream &stream); private: + WinCursor() = delete; + byte *_surface; byte *_mask; byte _palette[256 * 3]; @@ -70,11 +72,11 @@ private: void clear(); }; -WinCursor::WinCursor() { +WinCursor::WinCursor(uint16 hotspotX, uint16 hotspotY) { _width = 0; _height = 0; - _hotspotX = 0; - _hotspotY = 0; + _hotspotX = hotspotX; + _hotspotY = hotspotY; _surface = nullptr; _mask = nullptr; _keyColor = 0; @@ -111,9 +113,6 @@ bool WinCursor::readFromStream(Common::SeekableReadStream &stream) { const bool supportOpacity = g_system->hasFeature(OSystem::kFeatureCursorMask); const bool supportInvert = g_system->hasFeature(OSystem::kFeatureCursorMaskInvert); - _hotspotX = stream.readUint16LE(); - _hotspotY = stream.readUint16LE(); - // Check header size if (stream.readUint32LE() != 40) return false; @@ -151,8 +150,10 @@ bool WinCursor::readFromStream(Common::SeekableReadStream &stream) { if (numColors == 0) numColors = 1 << bitsPerPixel; + // Skip number of important colors + stream.skip(4); + // 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(); @@ -311,11 +312,14 @@ WinCursorGroup *WinCursorGroup::createCursorGroup(Common::WinResources *exe, con return 0; } - WinCursor *cursor = new WinCursor(); - if (!cursor->readFromStream(*cursorStream)) { - delete cursor; + uint16 hotspotX = cursorStream->readUint16LE(); + uint16 hotspotY = cursorStream->readUint16LE(); + + Cursor *cursor = loadWindowsCursorFromDIB(*cursorStream, hotspotX, hotspotY); + + if (!cursor) { delete group; - return 0; + return nullptr; } CursorItem item; @@ -448,4 +452,14 @@ Cursor *makeBusyWinCursor() { return new BusyWinCursor(); } +Cursor *loadWindowsCursorFromDIB(Common::SeekableReadStream &stream, uint16 hotspotX, uint16 hotspotY) { + WinCursor *cursor = new WinCursor(hotspotX, hotspotY); + if (!cursor->readFromStream(stream)) { + delete cursor; + return nullptr; + } + + return cursor; +} + } // End of namespace Graphics diff --git a/graphics/wincursor.h b/graphics/wincursor.h index 92e6479575e..210128fdd8f 100644 --- a/graphics/wincursor.h +++ b/graphics/wincursor.h @@ -80,6 +80,13 @@ Cursor *makeDefaultWinCursor(); */ Cursor *makeBusyWinCursor(); +/** + * Create a Cursor from DIB-format data, i.e. starting with a BITMAPINFOHEADER + * + * @note The calling code is responsible for deleting the returned pointer. + */ +Cursor *loadWindowsCursorFromDIB(Common::SeekableReadStream &stream, uint16 hotspotX, uint16 hotspotY); + /** @} */ } // End of namespace Graphics diff --git a/image/ani.cpp b/image/ani.cpp new file mode 100644 index 00000000000..c556e32815f --- /dev/null +++ b/image/ani.cpp @@ -0,0 +1,304 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "common/memstream.h" +#include "common/stream.h" +#include "common/substream.h" + +#include "image/ani.h" + +namespace Image { + +AniDecoder::Metadata::Metadata() + : numFrames(0), numSteps(0), width(0), height(0), bitCount(0), + numPlanes(0), perFrameDelay(0), haveSeqData(false), isCURFormat(false) { +} + +AniDecoder::FrameDef::FrameDef() : delay(0), imageIndex(0) { +} + +AniDecoder::AniDecoder() : _stream(nullptr), _disposeAfterUse(DisposeAfterUse::NO) { +} + +AniDecoder::~AniDecoder() { + close(); +} + +void AniDecoder::close() { + if (_disposeAfterUse == DisposeAfterUse::YES && _stream != nullptr) + delete _stream; + + _stream = nullptr; +} + +const AniDecoder::Metadata &AniDecoder::getMetadata() const { + return _metadata; +} + +AniDecoder::FrameDef AniDecoder::getSequenceFrame(uint sequenceIndex) const { + FrameDef frameDef; + + if (sequenceIndex >= _rateData.size()) + frameDef.delay = _metadata.perFrameDelay; + else + frameDef.delay = _rateData[sequenceIndex]; + + if (sequenceIndex >= _seqData.size()) + frameDef.imageIndex = sequenceIndex; + else + frameDef.imageIndex = _seqData[sequenceIndex]; + + return frameDef; +} + +Common::SeekableReadStream *AniDecoder::openImageStream(uint imageIndex) const { + if (imageIndex >= _frameDataLocations.size()) + error("Invalid ANI image index"); + + const FrameDataRange &frameDataRange = _frameDataLocations[imageIndex]; + + return new Common::SafeSeekableSubReadStream(_stream, frameDataRange.pos, frameDataRange.pos + frameDataRange.size); +} + +bool AniDecoder::open(Common::SeekableReadStream &stream, DisposeAfterUse::Flag disposeAfterUse) { + close(); + + _stream = &stream; + _disposeAfterUse = disposeAfterUse; + + bool loadedOK = load(); + if (!loadedOK) + close(); + + return loadedOK; +} + +bool AniDecoder::load() { + if (!parseRIFFChunks(*_stream, Common::Functor2Mem(this, &AniDecoder::parseTopLevelChunk))) { + warning("AniDecoder::load: Failed to load ANI container"); + return false; + } + + return true; +} + +bool AniDecoder::parseRIFFChunks(Common::SeekableReadStream &stream, const RIFFChunkParseFunc_t &callback) { + int64 nextChunkStartPos = 0; + int64 endPos = stream.size(); + + while (nextChunkStartPos < endPos) { + if (!stream.seek(nextChunkStartPos)) { + warning("AniDecoder::parseRIFFChunks: Failed to reset to start of RIFF chunk"); + return false; + } + + byte riffChunkHeader[8]; + + if (stream.read(riffChunkHeader, 8) != 8) { + warning("AniDecoder::parseRIFFChunks: Failed to read RIFF chunk header"); + return false; + } + + uint32 chunkSize = READ_LE_UINT32(riffChunkHeader + 4); + + int64 actualChunkSize = chunkSize; + if (chunkSize & 1) + actualChunkSize++; + + int64 chunkAvailable = stream.size() - stream.pos(); + if (chunkAvailable < actualChunkSize) { + warning("AniDecoder::parseRIFFChunk: RIFF chunk is too large"); + return false; + } + + RIFFChunkDef chunkDef; + chunkDef.id = READ_BE_UINT32(riffChunkHeader); + chunkDef.size = chunkSize; + + Common::SeekableSubReadStream substream(&stream, static_cast(stream.pos()), static_cast(stream.pos()) + chunkSize); + if (!callback(chunkDef, substream)) + return false; + + nextChunkStartPos += actualChunkSize + 8; + } + + return true; +} + +bool AniDecoder::parseRIFFContainer(Common::SeekableReadStream &chunkStream, const RIFFChunkDef &chunkDef, const RIFFContainerParseFunc_t &callback) { + if (chunkDef.size < 4) { + warning("AniDecoder::parseRIFFContainer: RIFF container is too small"); + return false; + } + + byte containerTypeID[4]; + if (chunkStream.read(containerTypeID, 4) != 4) { + warning("AniDecoder::parseRIFFContainer: Failed to read RIFF container type"); + return false; + } + + RIFFContainerDef containerDef; + containerDef.id = READ_BE_UINT32(containerTypeID); + containerDef.size = chunkDef.size - 4; + + Common::SeekableSubReadStream substream(&chunkStream, 4, chunkDef.size); + return callback(containerDef, substream); +} + +bool AniDecoder::parseTopLevelChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream) { + if (chunk.id != MKTAG('R', 'I', 'F', 'F')) { + warning("AniDecoder::parseTopLevelChunk: Top-level chunk isn't RIFF"); + return false; + } + + return parseRIFFContainer(stream, chunk, Common::Functor2Mem(this, &AniDecoder::parseTopLevelContainer)); +} + +bool AniDecoder::parseTopLevelContainer(const RIFFContainerDef &container, Common::SeekableReadStream &stream) { + if (container.id == MKTAG('A', 'C', 'O', 'N')) + return parseRIFFChunks(stream, Common::Functor2Mem(this, &AniDecoder::parseSecondLevelChunk)); + + warning("AniDecoder::parseTopLevelContainer: Top-level container isn't ACON"); + return false; +} + +bool AniDecoder::parseSecondLevelChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream) { + if (chunk.id == MKTAG('L', 'I', 'S', 'T')) + return parseRIFFContainer(stream, chunk, Common::Functor2Mem(this, &AniDecoder::parseListContainer)); + + if (chunk.id == MKTAG('a', 'n', 'i', 'h')) + return parseAnimHeaderChunk(chunk, stream); + + if (chunk.id == MKTAG('s', 'e', 'q', ' ')) + return parseSeqChunk(chunk, stream); + + if (chunk.id == MKTAG('r', 'a', 't', 'e')) + return parseRateChunk(chunk, stream); + + return true; +} + +bool AniDecoder::parseListContainer(const RIFFContainerDef &container, Common::SeekableReadStream &stream) { + if (container.id == MKTAG('f', 'r', 'a', 'm')) + return parseRIFFChunks(stream, Common::Functor2Mem(this, &AniDecoder::parseIconChunk)); + + return true; +} + +bool AniDecoder::parseAnimHeaderChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream) { + byte animHeader[36]; + for (byte &b : animHeader) + b = 0; + + uint32 amountToRead = 36; + if (chunk.size < amountToRead) + amountToRead = chunk.size; + + if (amountToRead > 0 && stream.read(animHeader, amountToRead) != amountToRead) { + warning("AniDecoder::parseAnimHeaderChunk: Read failed"); + return false; + } + + uint32 structSize = READ_LE_UINT32(animHeader); + if (structSize < 36) { + for (uint i = structSize; i < 36; i++) + animHeader[i] = 0; + } + + _metadata.numFrames = READ_LE_UINT32(animHeader + 4); + _metadata.numSteps = READ_LE_UINT32(animHeader + 8); + _metadata.width = READ_LE_UINT32(animHeader + 12); + _metadata.height = READ_LE_UINT32(animHeader + 16); + _metadata.bitCount = READ_LE_UINT32(animHeader + 20); + _metadata.numPlanes = READ_LE_UINT32(animHeader + 24); + _metadata.perFrameDelay = READ_LE_UINT32(animHeader + 28); + + uint32 flags = READ_LE_UINT32(animHeader + 32); + _metadata.isCURFormat = ((flags & 1) != 0); + _metadata.haveSeqData = ((flags & 2) != 0); + + return true; +} + +bool AniDecoder::parseSeqChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream) { + uint32 numFrames = chunk.size / 4u; + + if (numFrames > 1000u) { + warning("AniDecoder::parseRateChunk: Too many frames"); + return false; + } + + if (numFrames > _seqData.size()) + _seqData.resize(numFrames); + + for (uint i = 0; i < numFrames; i++) { + byte seqData[4]; + + if (stream.read(seqData, 4) != 4) { + warning("AniDecoder::parseRateChunk: Failed to read sequence information"); + return false; + } + + _seqData[i] = READ_LE_UINT32(seqData); + } + + return true; +} + +bool AniDecoder::parseRateChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream) { + uint32 numFrames = chunk.size / 4u; + + if (numFrames > 1000u) { + warning("AniDecoder::parseRateChunk: Too many frames"); + return false; + } + + if (numFrames > _rateData.size()) + _rateData.resize(numFrames); + + for (uint i = 0; i < numFrames; i++) { + byte rateData[4]; + + if (stream.read(rateData, 4) != 4) { + warning("AniDecoder::parseRateChunk: Failed to read rate information"); + return false; + } + + _rateData[i] = READ_LE_UINT32(rateData); + } + + return true; +} + +bool AniDecoder::parseIconChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream) { + FrameDataRange frameDataRange; + + // Get the global stream position + frameDataRange.pos = static_cast(_stream->pos()); + frameDataRange.size = chunk.size; + + _frameDataLocations.push_back(frameDataRange); + + return true; +} + + +} // End of namespace Image diff --git a/image/ani.h b/image/ani.h new file mode 100644 index 00000000000..dc47b62bb08 --- /dev/null +++ b/image/ani.h @@ -0,0 +1,136 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef GFX_ANI_H +#define GFX_ANI_H + +#include "common/array.h" +#include "common/types.h" +#include "common/func.h" + +namespace Common { + +class SeekableReadStream; +struct IFFChunk; + +} // End of namespace Common + +namespace Graphics { + +class Cursor; +struct Surface; + +} // End of namespace Graphics + +namespace Image { + +class AniDecoder { +public: + struct Metadata { + Metadata(); + + uint32 numFrames; // Number of images + uint32 numSteps; // Number of frames (use the FrameDef to determine which frame) + uint32 width; + uint32 height; + uint32 bitCount; + uint32 numPlanes; + uint32 perFrameDelay; + bool haveSeqData; + bool isCURFormat; + }; + + struct FrameDef { + FrameDef(); + + uint32 imageIndex; + uint32 delay; // In 1/60 sec + }; + + AniDecoder(); + ~AniDecoder(); + + bool open(Common::SeekableReadStream &stream, DisposeAfterUse::Flag = DisposeAfterUse::NO); + void close(); + + const Metadata &getMetadata() const; + FrameDef getSequenceFrame(uint sequenceIndex) const; + + /** + * Opens a substream for an image. If the metadata field + * "isCURFormat" is set, you can pass the stream to IcoCurDecoder to + * read it. Otherwise, you must determine the format. The stream + * is valid for as long as the stream used to construct the AniDecoder + * is valid. + * + * @param imageIndex The index of the image in the ANI file. + * @return A substream for the image. + */ + Common::SeekableReadStream *openImageStream(uint imageIndex) const; + +private: + struct RIFFContainerDef { + uint32 id; + uint32 size; + }; + + struct RIFFChunkDef { + uint32 id; + uint32 size; + }; + + struct FrameDataRange { + uint32 pos; + uint32 size; + }; + + typedef Common::Functor2 RIFFContainerParseFunc_t; + typedef Common::Functor2 RIFFChunkParseFunc_t; + + bool load(); + + static bool parseRIFFChunks(Common::SeekableReadStream &stream, const RIFFChunkParseFunc_t &callback); + static bool parseRIFFContainer(Common::SeekableReadStream &stream, const RIFFChunkDef &chunkDef, const RIFFContainerParseFunc_t &callback); + + bool parseTopLevelChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream); + bool parseTopLevelContainer(const RIFFContainerDef &container, Common::SeekableReadStream &stream); + + bool parseSecondLevelChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream); + + bool parseListContainer(const RIFFContainerDef &container, Common::SeekableReadStream &stream); + + bool parseAnimHeaderChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream); + bool parseSeqChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream); + bool parseRateChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream); + bool parseIconChunk(const RIFFChunkDef &chunk, Common::SeekableReadStream &stream); + + Metadata _metadata; + Common::Array _rateData; + Common::Array _seqData; + Common::Array _frameDataLocations; + + Common::SeekableReadStream *_stream; + DisposeAfterUse::Flag _disposeAfterUse; +}; + +} // End of namespace Image + +#endif diff --git a/image/icocur.cpp b/image/icocur.cpp new file mode 100644 index 00000000000..60876facf3a --- /dev/null +++ b/image/icocur.cpp @@ -0,0 +1,142 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "common/stream.h" +#include "common/substream.h" +#include "common/memstream.h" + +#include "image/icocur.h" + +#include "graphics/wincursor.h" + +namespace Image { + +IcoCurDecoder::IcoCurDecoder() : _type(kTypeInvalid), _stream(nullptr), _disposeAfterUse(DisposeAfterUse::NO) { +} + +IcoCurDecoder::~IcoCurDecoder() { + close(); +} + +void IcoCurDecoder::close() { + if (_disposeAfterUse == DisposeAfterUse::YES && _stream != nullptr) + delete _stream; + + _stream = nullptr; + _type = kTypeInvalid; + _items.clear(); +} + +bool IcoCurDecoder::open(Common::SeekableReadStream &stream, DisposeAfterUse::Flag disposeAfterUse) { + close(); + + _stream = &stream; + _disposeAfterUse = disposeAfterUse; + + bool loadedOK = load(); + if (!loadedOK) + close(); + + return loadedOK; +} + +bool IcoCurDecoder::load() { + uint8 iconDirData[6]; + + if (_stream->read(iconDirData, 6) != 6) + return false; + + if (iconDirData[0] != 0 || iconDirData[1] != 0 || (iconDirData[2] != 1 && iconDirData[2] != 2) || iconDirData[3] != 0) { + warning("Malformed ICO/CUR header"); + return false; + } + + uint16 numImages = READ_LE_UINT16(iconDirData + 4); + _type = static_cast(iconDirData[2]); + + if (numImages == 0) + return true; + + uint32 dirSize = static_cast(numImages) * 16; + + Common::Array iconDir; + iconDir.resize(dirSize); + + if (_stream->read(&iconDir[0], dirSize) != dirSize) + return false; + + _items.resize(numImages); + for (uint i = 0; i < numImages; i++) { + const uint8 *entryData = &iconDir[i * 16u]; + Item &item = _items[i]; + + item.width = entryData[0]; + if (item.width == 0) + item.width = 256; + + item.height = entryData[1]; + if (item.height == 0) + item.height = 256; + + item.numColors = entryData[2]; + + item.data.ico.numPlanes = READ_LE_UINT16(entryData + 4); + item.data.ico.bitsPerPixel = READ_LE_UINT16(entryData + 6); + item.dataSize = READ_LE_UINT32(entryData + 8); + item.dataOffset = READ_LE_UINT32(entryData + 12); + } + + return true; +} + +IcoCurDecoder::Type IcoCurDecoder::getType() const { + return _type; +} + +uint IcoCurDecoder::numItems() const { + return _items.size(); +} + +const IcoCurDecoder::Item &IcoCurDecoder::getItem(uint itemIndex) const { + return _items[itemIndex]; +} + +Graphics::Cursor *IcoCurDecoder::loadItemAsCursor(uint itemIndex) const { + const IcoCurDecoder::Item &dirItem = _items[itemIndex]; + + if (_type != kTypeCUR) + warning("ICO/CUR file type wasn't a cursor, but is being requested as a cursor anyway"); + + if (static_cast(dirItem.dataOffset) > _stream->size()) { + warning("ICO/CUR data offset was outside of the file"); + return nullptr; + } + + if (_stream->size() - static_cast(dirItem.dataOffset) < static_cast(dirItem.dataSize)) { + warning("ICO/CUR data bounds were outside of the file"); + return nullptr; + } + + Common::SeekableSubReadStream substream(_stream, dirItem.dataOffset, dirItem.dataOffset + dirItem.dataSize); + return Graphics::loadWindowsCursorFromDIB(substream, dirItem.data.cur.hotspotX, dirItem.data.cur.hotspotY); +} + +} // End of namespace Image diff --git a/image/icocur.h b/image/icocur.h new file mode 100644 index 00000000000..b0858a98aa3 --- /dev/null +++ b/image/icocur.h @@ -0,0 +1,106 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef GFX_ICOCUR_H +#define GFX_ICOCUR_H + +#include "common/array.h" +#include "common/types.h" + +namespace Common { + +class SeekableReadStream; + +} // End of namespace Common + +namespace Graphics { + +class Cursor; +struct Surface; + +} // End of namespace Graphics + +namespace Image { + +class IcoCurDecoder { +public: + enum Type { + kTypeInvalid, + + kTypeICO, + kTypeCUR, + }; + + struct Item { + struct IconData { + uint16 numPlanes; + uint16 bitsPerPixel; + }; + + struct CursorData { + uint16 hotspotX; + uint16 hotspotY; + }; + + union DataUnion { + IconData ico; + CursorData cur; + }; + + uint16 width; + uint16 height; + uint8 numColors; // May be 0 + DataUnion data; + uint32 dataSize; + uint32 dataOffset; + }; + + IcoCurDecoder(); + ~IcoCurDecoder(); + + bool open(Common::SeekableReadStream &stream, DisposeAfterUse::Flag = DisposeAfterUse::NO); + void close(); + + Type getType() const; + uint numItems() const; + const Item &getItem(uint itemIndex) const; + + /** + * Loads an item from the directory as a cursor. + * + * @param itemIndex The index of the item in the directory. + * @return Loaded cursor. + */ + Graphics::Cursor *loadItemAsCursor(uint itemIndex) const; + +private: + bool load(); + + Type _type; + Common::Array _items; + + Common::SeekableReadStream *_stream; + DisposeAfterUse::Flag _disposeAfterUse; +}; + +} // End of namespace Image + +#endif diff --git a/image/module.mk b/image/module.mk index df24ea3f61f..5bcc928f43a 100644 --- a/image/module.mk +++ b/image/module.mk @@ -1,9 +1,11 @@ MODULE := image MODULE_OBJS := \ + ani.o \ bmp.o \ cel_3do.o \ gif.o \ + icocur.o \ iff.o \ jpeg.o \ neo.o \