diff options
-rw-r--r-- | backends/vkeybd/virtual-keyboard-parser.cpp | 14 | ||||
-rw-r--r-- | engines/hugo/dialogs.cpp | 15 | ||||
-rw-r--r-- | graphics/decoders/bmp.cpp | 159 | ||||
-rw-r--r-- | graphics/decoders/bmp.h (renamed from graphics/imagedec.h) | 43 | ||||
-rw-r--r-- | graphics/decoders/image_decoder.h | 85 | ||||
-rw-r--r-- | graphics/imagedec.cpp | 176 | ||||
-rw-r--r-- | graphics/module.mk | 4 | ||||
-rw-r--r-- | gui/ThemeEngine.cpp | 15 |
8 files changed, 294 insertions, 217 deletions
diff --git a/backends/vkeybd/virtual-keyboard-parser.cpp b/backends/vkeybd/virtual-keyboard-parser.cpp index 1958113578..bb8286d1f5 100644 --- a/backends/vkeybd/virtual-keyboard-parser.cpp +++ b/backends/vkeybd/virtual-keyboard-parser.cpp @@ -34,7 +34,7 @@ #include "common/tokenizer.h" #include "common/stream.h" -#include "graphics/imagedec.h" +#include "graphics/decoders/bmp.h" namespace Common { @@ -266,11 +266,15 @@ bool VirtualKeyboardParser::parserCallback_layout(ParserNode *node) { const Graphics::PixelFormat format = g_system->getOverlayFormat(); - _mode->image = Graphics::ImageDecoder::loadFile(*file, format); - delete file; + { + Graphics::BitmapDecoder bmp; + if (!bmp.loadStream(*file)) + return parserError("Error loading bitmap '" + _mode->bitmapName + "'"); + + _mode->image = bmp.getSurface()->convertTo(format); + } - if (!_mode->image) - return parserError("Error loading bitmap '" + _mode->bitmapName + "'"); + delete file; int r, g, b; if (node->values.contains("transparent_color")) { diff --git a/engines/hugo/dialogs.cpp b/engines/hugo/dialogs.cpp index c43cdd7b46..e0b0198470 100644 --- a/engines/hugo/dialogs.cpp +++ b/engines/hugo/dialogs.cpp @@ -21,7 +21,7 @@ */ #include "common/substream.h" -#include "graphics/imagedec.h" +#include "graphics/decoders/bmp.h" #include "gui/gui-manager.h" #include "gui/ThemeEval.h" @@ -128,7 +128,16 @@ void TopMenu::loadBmpArr(Common::SeekableReadStream &in) { uint16 bmpSize = in.readUint16BE(); uint32 filPos = in.pos(); Common::SeekableSubReadStream stream(&in, filPos, filPos + bmpSize); - arrayBmp[i * 2] = Graphics::ImageDecoder::loadFile(stream, g_system->getOverlayFormat()); + + Graphics::BitmapDecoder bitmapDecoder; + if (!bitmapDecoder.loadStream(stream)) + error("TopMenu::loadBmpArr(): Could not load bitmap"); + + const Graphics::Surface *bitmapSrc = bitmapDecoder.getSurface(); + if (bitmapSrc->format.bytesPerPixel == 1) + error("TopMenu::loadBmpArr(): Unhandled paletted image"); + + arrayBmp[i * 2] = bitmapSrc->convertTo(g_system->getOverlayFormat()); arrayBmp[i * 2 + 1] = new Graphics::Surface(); arrayBmp[i * 2 + 1]->create(arrayBmp[i * 2]->w * 2, arrayBmp[i * 2]->h * 2, g_system->getOverlayFormat()); byte *src = (byte *)arrayBmp[i * 2]->pixels; @@ -154,7 +163,7 @@ void TopMenu::loadBmpArr(Common::SeekableReadStream &in) { } } - in.skip(bmpSize); + in.seek(filPos + bmpSize); } } diff --git a/graphics/decoders/bmp.cpp b/graphics/decoders/bmp.cpp new file mode 100644 index 0000000000..0d44881d7c --- /dev/null +++ b/graphics/decoders/bmp.cpp @@ -0,0 +1,159 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "common/stream.h" +#include "common/textconsole.h" + +#include "graphics/pixelformat.h" +#include "graphics/surface.h" +#include "graphics/decoders/bmp.h" + +namespace Graphics { + +BitmapDecoder::BitmapDecoder() { + _surface = 0; + _palette = 0; +} + +BitmapDecoder::~BitmapDecoder() { + destroy(); +} + +void BitmapDecoder::destroy() { + if (_surface) { + _surface->free(); + delete _surface; _surface = 0; + } + + delete[] _palette; _palette = 0; +} + +bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { + destroy(); + + if (stream.readByte() != 'B') + return false; + + if (stream.readByte() != 'M') + return false; + + /* uint32 fileSize = */ stream.readUint32LE(); + /* uint16 res1 = */ stream.readUint16LE(); + /* uint16 res2 = */ stream.readUint16LE(); + uint32 imageOffset = stream.readUint32LE(); + + uint32 infoSize = stream.readUint32LE(); + if (infoSize != 40) { + warning("Only Windows v3 bitmaps are supported"); + return false; + } + + uint32 width = stream.readUint32LE(); + int32 height = stream.readSint32LE(); + + if (width == 0 || height == 0) + return false; + + if (height < 0) { + warning("Right-side up bitmaps not supported"); + return false; + } + + /* uint16 planes = */ stream.readUint16LE(); + uint16 bitsPerPixel = stream.readUint16LE(); + + if (bitsPerPixel != 8 && bitsPerPixel != 24) { + warning("%dbpp bitmaps not supported", bitsPerPixel); + return false; + } + + uint32 compression = stream.readUint32LE(); + + if (compression != 0) { + warning("Compressed bitmaps not supported"); + return false; + } + + /* uint32 imageSize = */ stream.readUint32LE(); + /* uint32 pixelsPerMeterX = */ stream.readUint32LE(); + /* uint32 pixelsPerMeterY = */ stream.readUint32LE(); + uint32 colorsUsed = stream.readUint32LE(); + /* uint32 colorsImportant = */ stream.readUint32LE(); + + if (colorsUsed == 0) + colorsUsed = 256; + + if (bitsPerPixel == 8) { + // Read the palette + _palette = new byte[colorsUsed * 3]; + for (uint16 i = 0; i < colorsUsed; i++) { + _palette[i * 3 + 2] = stream.readByte(); + _palette[i * 3 + 1] = stream.readByte(); + _palette[i * 3 + 0] = stream.readByte(); + stream.readByte(); + } + } + + // Start us at the beginning of the image + stream.seek(imageOffset); + + Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8(); + + // BGRA for 24bpp + if (bitsPerPixel == 24) + format = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); + + _surface = new Graphics::Surface(); + _surface->create(width, height, format); + + int srcPitch = width * (bitsPerPixel >> 3); + const int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0; + + if (bitsPerPixel == 8) { + byte *dst = (byte *)_surface->pixels; + + for (int32 i = 0; i < height; i++) { + stream.read(dst + (height - i - 1) * width, width); + stream.skip(extraDataLength); + } + } else { + byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch; + + for (int32 i = 0; i < height; i++) { + for (uint32 j = 0; j < width; j++) { + byte b = stream.readByte(); + byte g = stream.readByte(); + byte r = stream.readByte(); + uint32 color = format.RGBToColor(r, g, b); + + *((uint32 *)dst) = color; + dst += format.bytesPerPixel; + } + + stream.skip(extraDataLength); + dst -= _surface->pitch * 2; + } + } + + return true; +} + +} // End of namespace Graphics diff --git a/graphics/imagedec.h b/graphics/decoders/bmp.h index b03b8bc36b..e11b12fad6 100644 --- a/graphics/imagedec.h +++ b/graphics/decoders/bmp.h @@ -19,11 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef GRAPHICS_IMAGEDEC_H -#define GRAPHICS_IMAGEDEC_H +#ifndef GRAPHICS_DECODERS_BMP_H +#define GRAPHICS_DECODERS_BMP_H #include "common/scummsys.h" #include "common/str.h" +#include "graphics/decoders/image_decoder.h" namespace Common{ class SeekableReadStream; @@ -34,32 +35,22 @@ namespace Graphics { struct PixelFormat; struct Surface; -class ImageDecoder { +class BitmapDecoder : public ImageDecoder { public: - virtual ~ImageDecoder() {} - - static Surface *loadFile(const Common::String &name, const PixelFormat &format); - static Surface *loadFile(Common::SeekableReadStream &stream, const PixelFormat &format); - - /** - * checks if the data can be decoded by this decoder - * - * @param stream memory read stream - * @return true if it can be decoded, otherwise false - */ - virtual bool decodeable(Common::SeekableReadStream &stream) = 0; - - /** - * decodes the data and returns an pointer to the resulting surface. - * Surface::free() must be called by the user also it must be deleted - * with delete; - * - * @param stream the memory stream which should be decoded - * @param format the pixel format used to generate the surface - * @return returns a new surface if the image could be decoded, otherwise 0 - */ - virtual Surface *decodeImage(Common::SeekableReadStream &stream, const PixelFormat &format) = 0; + BitmapDecoder(); + virtual ~BitmapDecoder(); + + // ImageDecoder API + void destroy(); + virtual bool loadStream(Common::SeekableReadStream &stream); + virtual const Surface *getSurface() const { return _surface; } + virtual const byte *getPalette() { return _palette; } + +private: + Surface *_surface; + byte *_palette; }; + } // End of namespace Graphics #endif diff --git a/graphics/decoders/image_decoder.h b/graphics/decoders/image_decoder.h new file mode 100644 index 0000000000..e768f7f9a2 --- /dev/null +++ b/graphics/decoders/image_decoder.h @@ -0,0 +1,85 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef GRAPHICS_DECODERS_IMAGEDECODER_H +#define GRAPHICS_DECODERS_IMAGEDECODER_H + +#include "common/scummsys.h" +#include "common/str.h" + +namespace Common{ +class SeekableReadStream; +} + +namespace Graphics { + +struct PixelFormat; +struct Surface; + +/** + * A representation of an image decoder that maintains ownership of the surface + * and palette it decodes to. + */ +class ImageDecoder { +public: + virtual ~ImageDecoder() {} + + /** + * Load an image from the specified stream + * + * @param stream the input stream + * @return whether loading the file succeeded + * @see getSurface + * @see getPalette + */ + virtual bool loadStream(Common::SeekableReadStream &stream) = 0; + + /** + * Destroy this decoder's surface and palette + */ + virtual void destroy() = 0; + + /** + * Get the decoded surface + * + * This surface is owned by this ImageDecoder and will remain valid + * until destroy() or loadStream() is called, or until this ImageDecoder's + * destructor is called. + * + * @return the decoded surface, or 0 if no surface is present + */ + virtual const Surface *getSurface() const = 0; + + /** + * Get the decoded palette + * + * This palette is owned by this ImageDecoder and will remain valid + * until destroy() or loadStream() is called, or until this ImageDecoder's + * destructor is called. + * + * @return the decoded palette, or 0 if no palette is present + */ + virtual const byte *getPalette() const { return 0; } +}; + +} // End of namespace Graphics + +#endif diff --git a/graphics/imagedec.cpp b/graphics/imagedec.cpp deleted file mode 100644 index 9552f095fa..0000000000 --- a/graphics/imagedec.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* 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 2 - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "graphics/imagedec.h" -#include "graphics/pixelformat.h" -#include "graphics/surface.h" - -#include "common/file.h" - -namespace Graphics { -// -// BMP Decoder -// -class BMPDecoder : public ImageDecoder { -public: - BMPDecoder() {} - virtual ~BMPDecoder() {} - - bool decodeable(Common::SeekableReadStream &stream); - Surface *decodeImage(Common::SeekableReadStream &stream, const PixelFormat &format); - - struct BitmapHeader { - uint16 type; - uint32 size; - uint16 res1; - uint16 res2; - uint32 imageOffset; - }; - - struct InfoHeader { - uint32 size; - uint32 width; - uint32 height; - uint16 planes; - uint16 bitsPerPixel; - uint32 compression; - uint32 imageSize; - uint32 pixelsPerMeterX; - uint32 pixelsPerMeterY; - uint32 colorsUsed; - uint32 colorsImportant; - }; -}; - -bool BMPDecoder::decodeable(Common::SeekableReadStream &stream) { - BitmapHeader header; - stream.seek(0); - header.type = stream.readUint16BE(); - header.size = stream.readUint32LE(); - - // TODO: maybe improve this detection - if (header.size == 0 || header.type != 'BM') - return false; - - return true; -} - -Surface *BMPDecoder::decodeImage(Common::SeekableReadStream &stream, const PixelFormat &format) { - if (!decodeable(stream)) { - return 0; - } - - BitmapHeader header; - InfoHeader info; - - stream.seek(0); - header.type = stream.readUint16BE(); - header.size = stream.readUint32LE(); - header.res1 = stream.readUint16LE(); - header.res2 = stream.readUint16LE(); - header.imageOffset = stream.readUint32LE(); - - if (header.size == 0 || header.type != 'BM') { - stream.seek(0); - return 0; - } - - info.size = stream.readUint32LE(); - info.width = stream.readUint32LE(); - info.height = stream.readUint32LE(); - info.planes = stream.readUint16LE(); - info.bitsPerPixel = stream.readUint16LE(); - info.compression = stream.readUint32LE(); - info.imageSize = stream.readUint32LE(); - info.pixelsPerMeterX = stream.readUint32LE(); - info.pixelsPerMeterY = stream.readUint32LE(); - info.colorsUsed = stream.readUint32LE(); - info.colorsImportant = stream.readUint32LE(); - - stream.seek(header.imageOffset); - - if (info.bitsPerPixel != 24) { - stream.seek(0); - return 0; - } - - uint8 r = 0, g = 0, b = 0; - Surface *newSurf = new Surface; - assert(newSurf); - newSurf->create(info.width, info.height, format); - assert(newSurf->pixels); - OverlayColor *curPixel = (OverlayColor *)newSurf->pixels + (newSurf->h-1) * newSurf->w; - int pitchAdd = info.width % 4; - for (int i = 0; i < newSurf->h; ++i) { - for (int i2 = 0; i2 < newSurf->w; ++i2) { - b = stream.readByte(); - g = stream.readByte(); - r = stream.readByte(); - *curPixel = format.RGBToColor(r, g, b); - ++curPixel; - } - stream.seek(pitchAdd, SEEK_CUR); - curPixel -= newSurf->w*2; - } - - stream.seek(0); - return newSurf; -} - -#pragma mark - - -Surface *ImageDecoder::loadFile(const Common::String &name, const PixelFormat &format) { - Surface *newSurf = 0; - - Common::File imageFile; - if (imageFile.open(name)) { - newSurf = loadFile(imageFile, format); - } - - return newSurf; -} - -Surface *ImageDecoder::loadFile(Common::SeekableReadStream &stream, const PixelFormat &format) { - // TODO: implement support for bzipped memory - - // FIXME: this is not a very nice solution but it should work - // for the moment, we should use a different way to get all - // decoders - static BMPDecoder bmpDecoder; - static ImageDecoder *decoderList[] = { - &bmpDecoder, // for uncompressed .BMP files - 0 - }; - - ImageDecoder *decoder = 0; - for (int i = 0; decoderList[i] != 0; ++i) { - if (decoderList[i]->decodeable(stream)) { - decoder = decoderList[i]; - break; - } - } - - if (!decoder) - return 0; - - return decoder->decodeImage(stream, format); -} -} // End of namespace Graphics diff --git a/graphics/module.mk b/graphics/module.mk index 1e84b2425d..5c1d313ca9 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -12,7 +12,6 @@ MODULE_OBJS := \ fonts/ttf.o \ fonts/winfont.o \ iff.o \ - imagedec.o \ jpeg.o \ maccursor.o \ pict.o \ @@ -26,7 +25,8 @@ MODULE_OBJS := \ VectorRenderer.o \ VectorRendererSpec.o \ wincursor.o \ - yuv_to_rgb.o + yuv_to_rgb.o \ + decoders/bmp.o ifdef USE_SCALERS MODULE_OBJS += \ diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp index 2cb1635e20..bcfd41e05b 100644 --- a/gui/ThemeEngine.cpp +++ b/gui/ThemeEngine.cpp @@ -30,11 +30,11 @@ #include "graphics/cursorman.h" #include "graphics/fontman.h" -#include "graphics/imagedec.h" #include "graphics/surface.h" #include "graphics/VectorRenderer.h" #include "graphics/fonts/bdf.h" #include "graphics/fonts/ttf.h" +#include "graphics/decoders/bmp.h" #include "gui/widget.h" #include "gui/ThemeEngine.h" @@ -620,20 +620,25 @@ bool ThemeEngine::addBitmap(const Common::String &filename) { if (surf) return true; - // If not, try to load the bitmap via the ImageDecoder class. + // If not, try to load the bitmap via the BitmapDecoder class. + Graphics::BitmapDecoder bitmapDecoder; + const Graphics::Surface *srcSurface = 0; Common::ArchiveMemberList members; _themeFiles.listMatchingMembers(members, filename); for (Common::ArchiveMemberList::const_iterator i = members.begin(), end = members.end(); i != end; ++i) { Common::SeekableReadStream *stream = (*i)->createReadStream(); if (stream) { - surf = Graphics::ImageDecoder::loadFile(*stream, _overlayFormat); + bitmapDecoder.loadStream(*stream); + srcSurface = bitmapDecoder.getSurface(); delete stream; - - if (surf) + if (srcSurface) break; } } + if (srcSurface && srcSurface->format.bytesPerPixel != 1) + surf = srcSurface->convertTo(_overlayFormat); + // Store the surface into our hashmap (attention, may store NULL entries!) _bitmaps[filename] = surf; |