diff options
39 files changed, 1062 insertions, 956 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/common/endian.h b/common/endian.h index 1760dc74b2..394437ec67 100644 --- a/common/endian.h +++ b/common/endian.h @@ -396,4 +396,10 @@ inline uint32 READ_BE_UINT24(const void *ptr) { return (b[0] << 16) | (b[1] << 8) | (b[2]); } +#ifdef SCUMM_LITTLE_ENDIAN +#define READ_UINT24(a) READ_LE_UINT24(a) +#else +#define READ_UINT24(a) READ_BE_UINT24(a) +#endif + #endif diff --git a/common/rect.h b/common/rect.h index 768d1ebbb9..2bd3affafe 100644 --- a/common/rect.h +++ b/common/rect.h @@ -244,11 +244,11 @@ struct Rect { /** * Create a rectangle around the given center. + * @note the center point is rounded up and left when given an odd width and height */ static Rect center(int16 cx, int16 cy, int16 w, int16 h) { - w /= 2; - h /= 2; - return Rect(cx - w, cy - h, cx + w, cy + h); + int x = cx - w / 2, y = cy - h / 2; + return Rect(x, y, x + w, y + h); } }; @@ -3501,7 +3501,7 @@ fi echocheck "FreeType2" echo "$_freetype2" -define_in_config_h_if_yes "$_freetype2" "USE_FREETYPE2" +define_in_config_if_yes "$_freetype2" "USE_FREETYPE2" # # Check for OpenGL (ES) diff --git a/doc/cz/PrectiMe b/doc/cz/PrectiMe index cb2484299b..4cb362ab3c 100644 --- a/doc/cz/PrectiMe +++ b/doc/cz/PrectiMe @@ -1534,7 +1534,11 @@ Flight of the Amazon Queen přidává následující nestandardní klíčová sl King's Quest VI Windows přidává následující nestandardní klíčová slova: windows_cursors boolean Pokud true, jsou použity původní černobílé kurzory místo kurzorů z DOS. Pokud false, jsou ve verzi Windows použity kurzory DOS, zvětšené, aby se shodovaly se zbytkem zvětšené grafiky + +Space Qust IV CD přidává následující nestandardní klíčové slovo: + silver_cursors boolean Pokud true, je místo původních zlatých kurzorů použita alternativní sada stříbrných + Simon the Sorcerer 1 a 2 přidává následující nestandardní klíčová slova: music_mute boolean Pokud true, hudba je ztlumena diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index f5f02b5cdd..726e7cbede 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -152,20 +152,26 @@ Common::Error GroovieEngine::run() { break; } - // Create the music player - switch (getPlatform()) { - case Common::kPlatformMacintosh: - // TODO: The 11th Hour Mac uses QuickTime MIDI files - // Right now, since the XMIDI are present and it is still detected as - // the DOS version, we don't have to do anything here. - _musicPlayer = new MusicPlayerMac(this); - break; - case Common::kPlatformIOS: + // Detect ScummVM Music Enhancement Project presence (T7G only) + if (Common::File::exists("gu16.ogg") && _gameDescription->version == kGroovieT7G) { + // Load player for external files _musicPlayer = new MusicPlayerIOS(this); - break; - default: - _musicPlayer = new MusicPlayerXMI(this, _gameDescription->version == kGroovieT7G ? "fat" : "sample"); - break; + } else { + // Create the music player + switch (getPlatform()) { + case Common::kPlatformMacintosh: + // TODO: The 11th Hour Mac uses QuickTime MIDI files + // Right now, since the XMIDI are present and it is still detected as + // the DOS version, we don't have to do anything here. + _musicPlayer = new MusicPlayerMac(this); + break; + case Common::kPlatformIOS: + _musicPlayer = new MusicPlayerIOS(this); + break; + default: + _musicPlayer = new MusicPlayerXMI(this, _gameDescription->version == kGroovieT7G ? "fat" : "sample"); + break; + } } // Load volume levels diff --git a/engines/groovie/roq.cpp b/engines/groovie/roq.cpp index 53f335ce68..8da8671b5d 100644 --- a/engines/groovie/roq.cpp +++ b/engines/groovie/roq.cpp @@ -30,8 +30,8 @@ #include "common/debug.h" #include "common/textconsole.h" -#include "graphics/jpeg.h" #include "graphics/palette.h" +#include "graphics/decoders/jpeg.h" #ifdef USE_RGB_COLOR // Required for the YUV to RGB conversion @@ -435,8 +435,8 @@ bool ROQPlayer::processBlockStill(ROQBlockHeader &blockHeader) { warning("Groovie::ROQ: JPEG frame (unfinshed)"); - Graphics::JPEG *jpg = new Graphics::JPEG(); - jpg->read(_file); + Graphics::JPEGDecoder *jpg = new Graphics::JPEGDecoder(); + jpg->loadStream(*_file); byte *y = (byte *)jpg->getComponent(1)->getBasePtr(0, 0); byte *u = (byte *)jpg->getComponent(2)->getBasePtr(0, 0); byte *v = (byte *)jpg->getComponent(3)->getBasePtr(0, 0); 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/engines/mohawk/bitmap.cpp b/engines/mohawk/bitmap.cpp index 4edde31236..952b6daec2 100644 --- a/engines/mohawk/bitmap.cpp +++ b/engines/mohawk/bitmap.cpp @@ -29,6 +29,7 @@ #include "common/substream.h" #include "common/system.h" #include "common/textconsole.h" +#include "graphics/decoders/bmp.h" namespace Mohawk { @@ -631,97 +632,37 @@ void MohawkBitmap::drawRLE8(Graphics::Surface *surface, bool isLE) { MohawkSurface *MystBitmap::decodeImage(Common::SeekableReadStream* stream) { uint32 uncompressedSize = stream->readUint32LE(); - Common::SeekableReadStream* bmpStream = decompressLZ(stream, uncompressedSize); + Common::SeekableReadStream *bmpStream = decompressLZ(stream, uncompressedSize); delete stream; - _header.type = bmpStream->readUint16BE(); + Graphics::BitmapDecoder bitmapDecoder; + if (!bitmapDecoder.loadStream(*bmpStream)) + error("Could not decode Myst bitmap"); - if (_header.type != 'BM') - error("BMP header not detected"); + const Graphics::Surface *bmpSurface = bitmapDecoder.getSurface(); + Graphics::Surface *newSurface = 0; - _header.size = bmpStream->readUint32LE(); - assert (_header.size > 0); - _header.res1 = bmpStream->readUint16LE(); - _header.res2 = bmpStream->readUint16LE(); - _header.imageOffset = bmpStream->readUint32LE(); - - _info.size = bmpStream->readUint32LE(); - - if (_info.size != 40) - error("Only Windows v3 BMP's are supported"); - - _info.width = bmpStream->readUint32LE(); - _info.height = bmpStream->readUint32LE(); - _info.planes = bmpStream->readUint16LE(); - _info.bitsPerPixel = bmpStream->readUint16LE(); - _info.compression = bmpStream->readUint32LE(); - _info.imageSize = bmpStream->readUint32LE(); - _info.pixelsPerMeterX = bmpStream->readUint32LE(); - _info.pixelsPerMeterY = bmpStream->readUint32LE(); - _info.colorsUsed = bmpStream->readUint32LE(); - _info.colorsImportant = bmpStream->readUint32LE(); - - if (_info.compression != 0) - error("Unhandled BMP compression %d", _info.compression); - - if (_info.colorsUsed == 0) - _info.colorsUsed = 256; - - if (_info.bitsPerPixel != 8 && _info.bitsPerPixel != 24) - error("%dbpp Bitmaps not supported", _info.bitsPerPixel); - - byte *palData = NULL; - - if (_info.bitsPerPixel == 8) { - palData = (byte *)malloc(256 * 3); - for (uint16 i = 0; i < _info.colorsUsed; i++) { - palData[i * 3 + 2] = bmpStream->readByte(); - palData[i * 3 + 1] = bmpStream->readByte(); - palData[i * 3 + 0] = bmpStream->readByte(); - bmpStream->readByte(); - } - } - - bmpStream->seek(_header.imageOffset); - - Graphics::Surface *surface = createSurface(_info.width, _info.height); - int srcPitch = _info.width * (_info.bitsPerPixel >> 3); - const int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0; - - if (_info.bitsPerPixel == 8) { - byte *dst = (byte *)surface->pixels; - - for (uint32 i = 0; i < _info.height; i++) { - bmpStream->read(dst + (_info.height - i - 1) * _info.width, _info.width); - bmpStream->skip(extraDataLength); - } + if (bmpSurface->format.bytesPerPixel == 1) { + _bitsPerPixel = 8; + newSurface = new Graphics::Surface(); + newSurface->copyFrom(*bmpSurface); } else { - Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); - - byte *dst = (byte *)surface->pixels + (surface->h - 1) * surface->pitch; - - for (uint32 i = 0; i < _info.height; i++) { - for (uint32 j = 0; j < _info.width; j++) { - byte b = bmpStream->readByte(); - byte g = bmpStream->readByte(); - byte r = bmpStream->readByte(); + _bitsPerPixel = 24; + newSurface = bmpSurface->convertTo(g_system->getScreenFormat()); + } - if (pixelFormat.bytesPerPixel == 2) - *((uint16 *)dst) = pixelFormat.RGBToColor(r, g, b); - else - *((uint32 *)dst) = pixelFormat.RGBToColor(r, g, b); + // Copy the palette to one of our own + const byte *palette = bitmapDecoder.getPalette(); + byte *newPal = 0; - dst += pixelFormat.bytesPerPixel; - } - - bmpStream->skip(extraDataLength); - dst -= surface->pitch * 2; - } + if (palette) { + newPal = (byte *)malloc(256 * 3); + memcpy(newPal, palette, 256 * 3); } delete bmpStream; - return new MohawkSurface(surface, palData); + return new MohawkSurface(newSurface, newPal); } #endif diff --git a/engines/mohawk/bitmap.h b/engines/mohawk/bitmap.h index 74218882e8..73c117b5c7 100644 --- a/engines/mohawk/bitmap.h +++ b/engines/mohawk/bitmap.h @@ -154,30 +154,10 @@ public: MohawkSurface *decodeImage(Common::SeekableReadStream *stream); protected: - byte getBitsPerPixel() { return _info.bitsPerPixel; } + byte getBitsPerPixel() { return _bitsPerPixel; } private: - struct BitmapHeader { - uint16 type; - uint32 size; - uint16 res1; - uint16 res2; - uint32 imageOffset; - } _header; - - struct InfoHeader { - uint32 size; - uint32 width; - uint32 height; - uint16 planes; - uint16 bitsPerPixel; - uint32 compression; - uint32 imageSize; - uint32 pixelsPerMeterX; - uint32 pixelsPerMeterY; - uint32 colorsUsed; - uint32 colorsImportant; - } _info; + uint16 _bitsPerPixel; }; #endif diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp index a08d034ef7..0f9a62c891 100644 --- a/engines/mohawk/graphics.cpp +++ b/engines/mohawk/graphics.cpp @@ -58,22 +58,7 @@ void MohawkSurface::convertToTrueColor() { assert(_palette); - Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); - Graphics::Surface *surface = new Graphics::Surface(); - surface->create(_surface->w, _surface->h, pixelFormat); - - for (uint16 i = 0; i < _surface->h; i++) { - for (uint16 j = 0; j < _surface->w; j++) { - byte palIndex = *((byte *)_surface->pixels + i * _surface->pitch + j); - byte r = _palette[palIndex * 3 + 0]; - byte g = _palette[palIndex * 3 + 1]; - byte b = _palette[palIndex * 3 + 2]; - if (pixelFormat.bytesPerPixel == 2) - *((uint16 *)surface->getBasePtr(j, i)) = pixelFormat.RGBToColor(r, g, b); - else - *((uint32 *)surface->getBasePtr(j, i)) = pixelFormat.RGBToColor(r, g, b); - } - } + Graphics::Surface *surface = _surface->convertTo(g_system->getScreenFormat(), _palette); // Free everything and set the new surface as the converted surface _surface->free(); diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp index 151390580f..484e49d529 100644 --- a/engines/mohawk/myst_graphics.cpp +++ b/engines/mohawk/myst_graphics.cpp @@ -28,8 +28,8 @@ #include "common/system.h" #include "common/textconsole.h" #include "engines/util.h" -#include "graphics/jpeg.h" -#include "graphics/pict.h" +#include "graphics/decoders/jpeg.h" +#include "graphics/decoders/pict.h" namespace Mohawk { @@ -49,14 +49,6 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { if (_pixelFormat.bytesPerPixel == 1) error("Myst requires greater than 256 colors to run"); - if (_vm->getFeatures() & GF_ME) { - _jpegDecoder = new Graphics::JPEG(); - _pictDecoder = new Graphics::PictDecoder(_pixelFormat); - } else { - _jpegDecoder = NULL; - _pictDecoder = NULL; - } - _pictureFile.entries = NULL; // Initialize our buffer @@ -69,8 +61,6 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { MystGraphics::~MystGraphics() { delete _bmpDecoder; - delete _jpegDecoder; - delete _pictDecoder; delete[] _pictureFile.entries; _backBuffer->free(); @@ -130,15 +120,21 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { for (uint32 i = 0; i < _pictureFile.pictureCount; i++) if (_pictureFile.entries[i].id == id) { if (_pictureFile.entries[i].type == 0) { - Common::SeekableReadStream *stream = new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size); + Graphics::JPEGDecoder jpeg; + Common::SeekableSubReadStream subStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size); - if (!_jpegDecoder->read(stream)) + if (!jpeg.loadStream(subStream)) error("Could not decode Myst ME Mac JPEG"); - mhkSurface = new MohawkSurface(_jpegDecoder->getSurface(_pixelFormat)); - delete stream; + mhkSurface = new MohawkSurface(jpeg.getSurface()->convertTo(_pixelFormat)); } else if (_pictureFile.entries[i].type == 1) { - mhkSurface = new MohawkSurface(_pictDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size))); + Graphics::PICTDecoder pict; + Common::SeekableSubReadStream subStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size); + + if (!pict.loadStream(subStream)) + error("Could not decode Myst ME Mac PICT"); + + mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat)); } else error ("Unknown Picture File type %d", _pictureFile.entries[i].type); break; @@ -170,9 +166,14 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { dataStream->seek(0); } - if (isPict) - mhkSurface = new MohawkSurface(_pictDecoder->decodeImage(dataStream)); - else { + if (isPict) { + Graphics::PICTDecoder pict; + + if (!pict.loadStream(*dataStream)) + error("Could not decode Myst ME PICT"); + + mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat)); + } else { mhkSurface = _bmpDecoder->decodeImage(dataStream); mhkSurface->convertToTrueColor(); } diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h index e2b02db5fc..20fd46c5b9 100644 --- a/engines/mohawk/myst_graphics.h +++ b/engines/mohawk/myst_graphics.h @@ -27,11 +27,6 @@ #include "common/file.h" -namespace Graphics { -class JPEG; -class PictDecoder; -} - namespace Mohawk { class MystBitmap; @@ -70,8 +65,6 @@ protected: private: MohawkEngine_Myst *_vm; MystBitmap *_bmpDecoder; - Graphics::PictDecoder *_pictDecoder; - Graphics::JPEG *_jpegDecoder; struct PictureFile { uint32 pictureCount; diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 8d72fa3f72..80fa4bf9a0 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -235,25 +235,7 @@ bool VideoManager::updateMovies() { if (_videoStreams[i]->hasDirtyPalette()) _videoStreams[i]->setSystemPalette(); } else { - convertedFrame = new Graphics::Surface(); - const byte *palette = _videoStreams[i]->getPalette(); - assert(palette); - - convertedFrame->create(frame->w, frame->h, pixelFormat); - - for (uint16 j = 0; j < frame->h; j++) { - for (uint16 k = 0; k < frame->w; k++) { - byte palIndex = *((const byte *)frame->getBasePtr(k, j)); - byte r = palette[palIndex * 3]; - byte g = palette[palIndex * 3 + 1]; - byte b = palette[palIndex * 3 + 2]; - if (pixelFormat.bytesPerPixel == 2) - *((uint16 *)convertedFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b); - else - *((uint32 *)convertedFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b); - } - } - + convertedFrame = frame->convertTo(pixelFormat, _videoStreams[i]->getPalette()); frame = convertedFrame; } } diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp index bff145ad53..7ecba5a24d 100644 --- a/engines/sci/graphics/maciconbar.cpp +++ b/engines/sci/graphics/maciconbar.cpp @@ -31,8 +31,8 @@ #include "common/memstream.h" #include "common/system.h" -#include "graphics/pict.h" #include "graphics/surface.h" +#include "graphics/decoders/pict.h" namespace Sci { @@ -201,18 +201,20 @@ void GfxMacIconBar::setInventoryIcon(int16 icon) { } Graphics::Surface *GfxMacIconBar::loadPict(ResourceId id) { - Graphics::PictDecoder pictDecoder(Graphics::PixelFormat::createFormatCLUT8()); + Graphics::PICTDecoder pictDecoder; Resource *res = g_sci->getResMan()->findResource(id, false); if (!res || res->size == 0) return 0; - byte palette[256 * 3]; - Common::SeekableReadStream *stream = new Common::MemoryReadStream(res->data, res->size); - Graphics::Surface *surface = pictDecoder.decodeImage(stream, palette); - remapColors(surface, palette); + Common::MemoryReadStream stream(res->data, res->size); + if (!pictDecoder.loadStream(stream)) + return 0; + + Graphics::Surface *surface = new Graphics::Surface(); + surface->copyFrom(*pictDecoder.getSurface()); + remapColors(surface, pictDecoder.getPalette()); - delete stream; return surface; } @@ -221,7 +223,7 @@ Graphics::Surface *GfxMacIconBar::createImage(uint32 iconIndex, bool isSelected) return loadPict(ResourceId(type, iconIndex + 1)); } -void GfxMacIconBar::remapColors(Graphics::Surface *surf, byte *palette) { +void GfxMacIconBar::remapColors(Graphics::Surface *surf, const byte *palette) { byte *pixels = (byte *)surf->pixels; // Remap to the screen palette diff --git a/engines/sci/graphics/maciconbar.h b/engines/sci/graphics/maciconbar.h index 43de37a904..eca10b804c 100644 --- a/engines/sci/graphics/maciconbar.h +++ b/engines/sci/graphics/maciconbar.h @@ -61,7 +61,7 @@ private: Graphics::Surface *loadPict(ResourceId id); Graphics::Surface *createImage(uint32 iconIndex, bool isSelected); - void remapColors(Graphics::Surface *surf, byte *palette); + void remapColors(Graphics::Surface *surf, const byte *palette); void drawIcon(uint16 index, bool selected); void drawSelectedImage(uint16 index); diff --git a/engines/sword25/gfx/image/imgloader.cpp b/engines/sword25/gfx/image/imgloader.cpp index 1df0fba70c..e103626416 100644 --- a/engines/sword25/gfx/image/imgloader.cpp +++ b/engines/sword25/gfx/image/imgloader.cpp @@ -33,18 +33,19 @@ #include "sword25/gfx/image/image.h" #include "sword25/gfx/image/imgloader.h" #include "graphics/pixelformat.h" -#include "graphics/png.h" +#include "graphics/decoders/png.h" namespace Sword25 { bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, byte *&uncompressedDataPtr, int &width, int &height, int &pitch) { Common::MemoryReadStream *fileStr = new Common::MemoryReadStream(fileDataPtr, fileSize, DisposeAfterUse::NO); - Graphics::PNG *png = new Graphics::PNG(); - if (!png->read(fileStr)) // the fileStr pointer, and thus pFileData will be deleted after this is done + + Graphics::PNGDecoder png; + if (!png.loadStream(*fileStr)) // the fileStr pointer, and thus pFileData will be deleted after this is done error("Error while reading PNG image"); - Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24); - Graphics::Surface *pngSurface = png->getSurface(format); + const Graphics::Surface *sourceSurface = png.getSurface(); + Graphics::Surface *pngSurface = sourceSurface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24), png.getPalette()); width = pngSurface->w; height = pngSurface->h; @@ -53,7 +54,7 @@ bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, byte *&un pngSurface->free(); delete pngSurface; - delete png; + delete fileStr; // Signal success return true; 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/jpeg.cpp b/graphics/decoders/jpeg.cpp index 53e693a045..a871377ca1 100644 --- a/graphics/jpeg.cpp +++ b/graphics/decoders/jpeg.cpp @@ -20,9 +20,9 @@ * */ -#include "graphics/conversion.h" -#include "graphics/jpeg.h" #include "graphics/pixelformat.h" +#include "graphics/yuv_to_rgb.h" +#include "graphics/decoders/jpeg.h" #include "common/debug.h" #include "common/endian.h" @@ -43,9 +43,9 @@ static const uint8 _zigZagOrder[64] = { 53, 60, 61, 54, 47, 55, 62, 63 }; -JPEG::JPEG() : +JPEGDecoder::JPEGDecoder() : ImageDecoder(), _stream(NULL), _w(0), _h(0), _numComp(0), _components(NULL), _numScanComp(0), - _scanComp(NULL), _currentComp(NULL) { + _scanComp(NULL), _currentComp(NULL), _rgbSurface(0) { // Initialize the quantization tables for (int i = 0; i < JPEG_MAX_QUANT_TABLES; i++) @@ -60,42 +60,33 @@ JPEG::JPEG() : } } -JPEG::~JPEG() { - reset(); +JPEGDecoder::~JPEGDecoder() { + destroy(); } -Surface *JPEG::getSurface(const PixelFormat &format) { +const Surface *JPEGDecoder::getSurface() const { // Make sure we have loaded data if (!isLoaded()) return 0; - // Only accept >8bpp surfaces - if (format.bytesPerPixel == 1) - return 0; + if (_rgbSurface) + return _rgbSurface; + + // Create an RGBA8888 surface + _rgbSurface = new Graphics::Surface(); + _rgbSurface->create(_w, _h, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); // Get our component surfaces - Graphics::Surface *yComponent = getComponent(1); - Graphics::Surface *uComponent = getComponent(2); - Graphics::Surface *vComponent = getComponent(3); - - Graphics::Surface *output = new Graphics::Surface(); - output->create(yComponent->w, yComponent->h, format); - - for (uint16 i = 0; i < output->h; i++) { - for (uint16 j = 0; j < output->w; j++) { - byte r = 0, g = 0, b = 0; - YUV2RGB(*((byte *)yComponent->getBasePtr(j, i)), *((byte *)uComponent->getBasePtr(j, i)), *((byte *)vComponent->getBasePtr(j, i)), r, g, b); - if (format.bytesPerPixel == 2) - *((uint16 *)output->getBasePtr(j, i)) = format.RGBToColor(r, g, b); - else - *((uint32 *)output->getBasePtr(j, i)) = format.RGBToColor(r, g, b); - } - } + const Graphics::Surface *yComponent = getComponent(1); + const Graphics::Surface *uComponent = getComponent(2); + const Graphics::Surface *vComponent = getComponent(3); + + convertYUV444ToRGB(_rgbSurface, (byte *)yComponent->pixels, (byte *)uComponent->pixels, (byte *)vComponent->pixels, yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch); - return output; + return _rgbSurface; } -void JPEG::reset() { +void JPEGDecoder::destroy() { // Reset member variables _stream = NULL; _w = _h = 0; @@ -125,14 +116,19 @@ void JPEG::reset() { delete[] _huff[i].sizes; _huff[i].sizes = NULL; delete[] _huff[i].codes; _huff[i].codes = NULL; } + + if (_rgbSurface) { + _rgbSurface->free(); + delete _rgbSurface; + } } -bool JPEG::read(Common::SeekableReadStream *stream) { +bool JPEGDecoder::loadStream(Common::SeekableReadStream &stream) { // Reset member variables and tables from previous reads - reset(); + destroy(); // Save the input stream - _stream = stream; + _stream = &stream; bool ok = true; bool done = false; @@ -211,41 +207,41 @@ bool JPEG::read(Common::SeekableReadStream *stream) { } } } + + _stream = 0; return ok; } -bool JPEG::readJFIF() { +bool JPEGDecoder::readJFIF() { uint16 length = _stream->readUint16BE(); uint32 tag = _stream->readUint32BE(); if (tag != MKTAG('J', 'F', 'I', 'F')) { - warning("JPEG::readJFIF() tag mismatch"); + warning("JPEGDecoder::readJFIF() tag mismatch"); return false; } if (_stream->readByte() != 0) { // NULL - warning("JPEG::readJFIF() NULL mismatch"); + warning("JPEGDecoder::readJFIF() NULL mismatch"); return false; } byte majorVersion = _stream->readByte(); byte minorVersion = _stream->readByte(); - - if (majorVersion != 1 || (minorVersion != 1 && minorVersion != 2)) - warning("JPEG::readJFIF() Non-v1.1/1.2 JPEGs may not be handled correctly"); - - /* byte densityUnits = */ _stream->readByte(); - /* uint16 xDensity = */ _stream->readUint16BE(); - /* uint16 yDensity = */ _stream->readUint16BE(); + if (majorVersion != 1 || minorVersion != 1) + warning("JPEGDecoder::readJFIF() Non-v1.1 JPEGs may not be handled correctly"); + /* byte densityUnits = */_stream->readByte(); + /* uint16 xDensity = */_stream->readUint16BE(); + /* uint16 yDensity = */_stream->readUint16BE(); byte thumbW = _stream->readByte(); byte thumbH = _stream->readByte(); _stream->seek(thumbW * thumbH * 3, SEEK_CUR); // Ignore thumbnail if (length != (thumbW * thumbH * 3) + 16) { - warning("JPEG::readJFIF() length mismatch"); + warning("JPEGDecoder::readJFIF() length mismatch"); return false; } return true; } // Marker 0xC0 (Start Of Frame, Baseline DCT) -bool JPEG::readSOF0() { +bool JPEGDecoder::readSOF0() { debug(5, "JPEG: readSOF0"); uint16 size = _stream->readUint16BE(); @@ -284,7 +280,7 @@ bool JPEG::readSOF0() { } // Marker 0xC4 (Define Huffman Tables) -bool JPEG::readDHT() { +bool JPEGDecoder::readDHT() { debug(5, "JPEG: readDHT"); uint16 size = _stream->readUint16BE() - 2; uint32 pos = _stream->pos(); @@ -346,7 +342,7 @@ bool JPEG::readDHT() { } // Marker 0xDA (Start Of Scan) -bool JPEG::readSOS() { +bool JPEGDecoder::readSOS() { debug(5, "JPEG: readSOS"); uint16 size = _stream->readUint16BE(); @@ -473,7 +469,7 @@ bool JPEG::readSOS() { } // Marker 0xDB (Define Quantization Tables) -bool JPEG::readDQT() { +bool JPEGDecoder::readDQT() { debug(5, "JPEG: readDQT"); uint16 size = _stream->readUint16BE() - 2; uint32 pos = _stream->pos(); @@ -503,7 +499,7 @@ bool JPEG::readDQT() { } // Marker 0xDD (Define Restart Interval) -bool JPEG::readDRI() { +bool JPEGDecoder::readDRI() { debug(5, "JPEG: readDRI"); uint16 size = _stream->readUint16BE() - 2; @@ -517,7 +513,7 @@ bool JPEG::readDRI() { return true; } -bool JPEG::readMCU(uint16 xMCU, uint16 yMCU) { +bool JPEGDecoder::readMCU(uint16 xMCU, uint16 yMCU) { bool ok = true; for (int c = 0; ok && (c < _numComp); c++) { // Set the current component @@ -549,7 +545,7 @@ bool JPEG::readMCU(uint16 xMCU, uint16 yMCU) { xb = (n - (k2 + k1) * p) >> sh; // IDCT based on public domain code from http://halicery.com/jpeg/idct.html -void JPEG::idct1D8x8(int32 src[8], int32 dest[64], int32 ps, int32 half) { +void JPEGDecoder::idct1D8x8(int32 src[8], int32 dest[64], int32 ps, int32 half) { int p, n; src[0] <<= 9; @@ -578,7 +574,7 @@ void JPEG::idct1D8x8(int32 src[8], int32 dest[64], int32 ps, int32 half) { dest[7 * 8] = (src[0] - src[1]) >> ps; } -void JPEG::idct2D8x8(int32 block[64]) { +void JPEGDecoder::idct2D8x8(int32 block[64]) { int32 tmp[64]; // Apply 1D IDCT to rows @@ -590,7 +586,7 @@ void JPEG::idct2D8x8(int32 block[64]) { idct1D8x8(&tmp[i * 8], &block[i], 12, 1 << 11); } -bool JPEG::readDataUnit(uint16 x, uint16 y) { +bool JPEGDecoder::readDataUnit(uint16 x, uint16 y) { // Prepare an empty data array int16 readData[64]; for (int i = 1; i < 64; i++) @@ -654,7 +650,7 @@ bool JPEG::readDataUnit(uint16 x, uint16 y) { return true; } -int16 JPEG::readDC() { +int16 JPEGDecoder::readDC() { // DC is type 0 uint8 tableNum = _currentComp->DCentropyTableSelector << 1; @@ -665,7 +661,7 @@ int16 JPEG::readDC() { return readSignedBits(numBits); } -void JPEG::readAC(int16 *out) { +void JPEGDecoder::readAC(int16 *out) { // AC is type 1 uint8 tableNum = (_currentComp->ACentropyTableSelector << 1) + 1; @@ -695,7 +691,7 @@ void JPEG::readAC(int16 *out) { } } -int16 JPEG::readSignedBits(uint8 numBits) { +int16 JPEGDecoder::readSignedBits(uint8 numBits) { uint16 ret = 0; if (numBits > 16) error("requested %d bits", numBits); //XXX @@ -713,7 +709,7 @@ int16 JPEG::readSignedBits(uint8 numBits) { } // TODO: optimize? -uint8 JPEG::readHuff(uint8 table) { +uint8 JPEGDecoder::readHuff(uint8 table) { bool foundCode = false; uint8 val = 0; @@ -743,7 +739,7 @@ uint8 JPEG::readHuff(uint8 table) { return val; } -uint8 JPEG::readBit() { +uint8 JPEGDecoder::readBit() { // Read a whole byte if necessary if (_bitsNumber == 0) { _bitsData = _stream->readByte(); @@ -773,12 +769,12 @@ uint8 JPEG::readBit() { return (_bitsData & (1 << _bitsNumber)) ? 1 : 0; } -Surface *JPEG::getComponent(uint c) { +const Surface *JPEGDecoder::getComponent(uint c) const { for (int i = 0; i < _numComp; i++) if (_components[i].id == c) // We found the desired component return &_components[i].surface; - error("JPEG::getComponent: No component %d present", c); + error("JPEGDecoder::getComponent: No component %d present", c); return NULL; } diff --git a/graphics/jpeg.h b/graphics/decoders/jpeg.h index b87791470f..c566d5ad21 100644 --- a/graphics/jpeg.h +++ b/graphics/decoders/jpeg.h @@ -24,6 +24,7 @@ #define GRAPHICS_JPEG_H #include "graphics/surface.h" +#include "graphics/decoders/image_decoder.h" namespace Common { class SeekableReadStream; @@ -36,26 +37,31 @@ struct PixelFormat; #define JPEG_MAX_QUANT_TABLES 4 #define JPEG_MAX_HUFF_TABLES 2 -class JPEG { +class JPEGDecoder : public ImageDecoder { public: - JPEG(); - ~JPEG(); + JPEGDecoder(); + ~JPEGDecoder(); + + // ImageDecoder API + void destroy(); + bool loadStream(Common::SeekableReadStream &str); + const Surface *getSurface() const; - bool read(Common::SeekableReadStream *str); bool isLoaded() const { return _numComp && _w && _h; } uint16 getWidth() const { return _w; } uint16 getHeight() const { return _h; } - - Surface *getComponent(uint c); - Surface *getSurface(const PixelFormat &format); + const Surface *getComponent(uint c) const; private: - void reset(); - Common::SeekableReadStream *_stream; uint16 _w, _h; uint16 _restartInterval; + // mutable so that we can convert to RGB only during + // a getSurface() call while still upholding the + // const requirement in other ImageDecoders + mutable Graphics::Surface *_rgbSurface; + // Image components uint8 _numComp; struct Component { diff --git a/graphics/pict.cpp b/graphics/decoders/pict.cpp index 872f2f224a..957342084e 100644 --- a/graphics/pict.cpp +++ b/graphics/decoders/pict.cpp @@ -26,9 +26,9 @@ #include "common/substream.h" #include "common/textconsole.h" -#include "graphics/jpeg.h" -#include "graphics/pict.h" #include "graphics/surface.h" +#include "graphics/decoders/jpeg.h" +#include "graphics/decoders/pict.h" namespace Graphics { @@ -36,18 +36,25 @@ namespace Graphics { // http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-461.html // http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-269.html -PictDecoder::PictDecoder(PixelFormat pixelFormat) { - _jpeg = new JPEG(); - _pixelFormat = pixelFormat; +PICTDecoder::PICTDecoder() { + _outputSurface = 0; +} + +PICTDecoder::~PICTDecoder() { + destroy(); } -PictDecoder::~PictDecoder() { - delete _jpeg; +void PICTDecoder::destroy() { + if (_outputSurface) { + _outputSurface->free(); + delete _outputSurface; + _outputSurface = 0; + } } -#define OPCODE(a, b, c) _opcodes.push_back(PICTOpcode(a, &PictDecoder::b, c)) +#define OPCODE(a, b, c) _opcodes.push_back(PICTOpcode(a, &PICTDecoder::b, c)) -void PictDecoder::setupOpcodesCommon() { +void PICTDecoder::setupOpcodesCommon() { OPCODE(0x0000, o_nop, "NOP"); OPCODE(0x0001, o_clip, "Clip"); OPCODE(0x0003, o_txFont, "TxFont"); @@ -63,14 +70,14 @@ void PictDecoder::setupOpcodesCommon() { OPCODE(0x0C00, o_headerOp, "HeaderOp"); } -void PictDecoder::setupOpcodesNormal() { +void PICTDecoder::setupOpcodesNormal() { setupOpcodesCommon(); OPCODE(0x0098, on_packBitsRect, "PackBitsRect"); OPCODE(0x009A, on_directBitsRect, "DirectBitsRect"); OPCODE(0x8200, on_compressedQuickTime, "CompressedQuickTime"); } -void PictDecoder::setupOpcodesQuickTime() { +void PICTDecoder::setupOpcodesQuickTime() { setupOpcodesCommon(); OPCODE(0x0098, oq_packBitsRect, "PackBitsRect"); OPCODE(0x009A, oq_directBitsRect, "DirectBitsRect"); @@ -79,93 +86,93 @@ void PictDecoder::setupOpcodesQuickTime() { #undef OPCODE -void PictDecoder::o_nop(Common::SeekableReadStream *) { +void PICTDecoder::o_nop(Common::SeekableReadStream &) { // Nothing to do } -void PictDecoder::o_clip(Common::SeekableReadStream *stream) { +void PICTDecoder::o_clip(Common::SeekableReadStream &stream) { // Ignore - stream->skip(stream->readUint16BE() - 2); + stream.skip(stream.readUint16BE() - 2); } -void PictDecoder::o_txFont(Common::SeekableReadStream *stream) { +void PICTDecoder::o_txFont(Common::SeekableReadStream &stream) { // Ignore - stream->readUint16BE(); + stream.readUint16BE(); } -void PictDecoder::o_txFace(Common::SeekableReadStream *stream) { +void PICTDecoder::o_txFace(Common::SeekableReadStream &stream) { // Ignore - stream->readByte(); + stream.readByte(); } -void PictDecoder::o_pnSize(Common::SeekableReadStream *stream) { +void PICTDecoder::o_pnSize(Common::SeekableReadStream &stream) { // Ignore - stream->readUint16BE(); - stream->readUint16BE(); + stream.readUint16BE(); + stream.readUint16BE(); } -void PictDecoder::o_txSize(Common::SeekableReadStream *stream) { +void PICTDecoder::o_txSize(Common::SeekableReadStream &stream) { // Ignore - stream->readUint16BE(); + stream.readUint16BE(); } -void PictDecoder::o_txRatio(Common::SeekableReadStream *stream) { +void PICTDecoder::o_txRatio(Common::SeekableReadStream &stream) { // Ignore - stream->readUint16BE(); - stream->readUint16BE(); - stream->readUint16BE(); - stream->readUint16BE(); + stream.readUint16BE(); + stream.readUint16BE(); + stream.readUint16BE(); + stream.readUint16BE(); } -void PictDecoder::o_versionOp(Common::SeekableReadStream *stream) { +void PICTDecoder::o_versionOp(Common::SeekableReadStream &stream) { // We only support v2 extended - if (stream->readUint16BE() != 0x02FF) + if (stream.readUint16BE() != 0x02FF) error("Unknown PICT version"); } -void PictDecoder::o_longText(Common::SeekableReadStream *stream) { +void PICTDecoder::o_longText(Common::SeekableReadStream &stream) { // Ignore - stream->readUint16BE(); - stream->readUint16BE(); - stream->skip(stream->readByte()); + stream.readUint16BE(); + stream.readUint16BE(); + stream.skip(stream.readByte()); } -void PictDecoder::o_longComment(Common::SeekableReadStream *stream) { +void PICTDecoder::o_longComment(Common::SeekableReadStream &stream) { // Ignore - stream->readUint16BE(); - stream->skip(stream->readUint16BE()); + stream.readUint16BE(); + stream.skip(stream.readUint16BE()); } -void PictDecoder::o_opEndPic(Common::SeekableReadStream *stream) { +void PICTDecoder::o_opEndPic(Common::SeekableReadStream &stream) { // We've reached the end of the picture _continueParsing = false; } -void PictDecoder::o_headerOp(Common::SeekableReadStream *stream) { +void PICTDecoder::o_headerOp(Common::SeekableReadStream &stream) { // Read the basic header, but we don't really have to do anything with it - /* uint16 version = */ stream->readUint16BE(); - stream->readUint16BE(); // Reserved - /* uint32 hRes = */ stream->readUint32BE(); - /* uint32 vRes = */ stream->readUint32BE(); + /* uint16 version = */ stream.readUint16BE(); + stream.readUint16BE(); // Reserved + /* uint32 hRes = */ stream.readUint32BE(); + /* uint32 vRes = */ stream.readUint32BE(); Common::Rect origResRect; - origResRect.top = stream->readUint16BE(); - origResRect.left = stream->readUint16BE(); - origResRect.bottom = stream->readUint16BE(); - origResRect.right = stream->readUint16BE(); - stream->readUint32BE(); // Reserved + origResRect.top = stream.readUint16BE(); + origResRect.left = stream.readUint16BE(); + origResRect.bottom = stream.readUint16BE(); + origResRect.right = stream.readUint16BE(); + stream.readUint32BE(); // Reserved } -void PictDecoder::on_packBitsRect(Common::SeekableReadStream *stream) { +void PICTDecoder::on_packBitsRect(Common::SeekableReadStream &stream) { // Unpack data (8bpp or lower) unpackBitsRect(stream, true); } -void PictDecoder::on_directBitsRect(Common::SeekableReadStream *stream) { +void PICTDecoder::on_directBitsRect(Common::SeekableReadStream &stream) { // Unpack data (16bpp or higher) unpackBitsRect(stream, false); } -void PictDecoder::on_compressedQuickTime(Common::SeekableReadStream *stream) { +void PICTDecoder::on_compressedQuickTime(Common::SeekableReadStream &stream) { // OK, here's the fun. We get to completely change how QuickDraw draws // the data in PICT files. @@ -173,63 +180,57 @@ void PictDecoder::on_compressedQuickTime(Common::SeekableReadStream *stream) { _opcodes.clear(); setupOpcodesQuickTime(); - // We set up the surface for JPEG here too - if (!_outputSurface) - _outputSurface = new Graphics::Surface(); - _outputSurface->create(_imageRect.width(), _imageRect.height(), _pixelFormat); - // We'll decode the first QuickTime data from here, but the QuickTime-specific // opcodes will take over from here on out. Normal opcodes, signing off. decodeCompressedQuickTime(stream); } -void PictDecoder::oq_packBitsRect(Common::SeekableReadStream *stream) { +void PICTDecoder::oq_packBitsRect(Common::SeekableReadStream &stream) { // Skip any data here (8bpp or lower) skipBitsRect(stream, true); } -void PictDecoder::oq_directBitsRect(Common::SeekableReadStream *stream) { +void PICTDecoder::oq_directBitsRect(Common::SeekableReadStream &stream) { // Skip any data here (16bpp or higher) skipBitsRect(stream, false); } -void PictDecoder::oq_compressedQuickTime(Common::SeekableReadStream *stream) { +void PICTDecoder::oq_compressedQuickTime(Common::SeekableReadStream &stream) { // Just pass the data along decodeCompressedQuickTime(stream); } -Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *palette) { - assert(stream); +bool PICTDecoder::loadStream(Common::SeekableReadStream &stream) { + destroy(); // Initialize opcodes to their normal state _opcodes.clear(); setupOpcodesNormal(); - _outputSurface = 0; _continueParsing = true; memset(_palette, 0, sizeof(_palette)); - uint16 fileSize = stream->readUint16BE(); + uint16 fileSize = stream.readUint16BE(); // If we have no file size here, we probably have a PICT from a file // and not a resource. The other two bytes are the fileSize which we // don't actually need (and already read if from a resource). if (!fileSize) - stream->seek(512 + 2); + stream.seek(512 + 2); - _imageRect.top = stream->readUint16BE(); - _imageRect.left = stream->readUint16BE(); - _imageRect.bottom = stream->readUint16BE(); - _imageRect.right = stream->readUint16BE(); + _imageRect.top = stream.readUint16BE(); + _imageRect.left = stream.readUint16BE(); + _imageRect.bottom = stream.readUint16BE(); + _imageRect.right = stream.readUint16BE(); _imageRect.debugPrint(0, "PICT Rect:"); // NOTE: This is only a subset of the full PICT format. // - Only V2 (Extended) Images Supported // - CompressedQuickTime (JPEG) compressed data is supported // - DirectBitsRect/PackBitsRect compressed data is supported - for (uint32 opNum = 0; !stream->eos() && !stream->err() && stream->pos() < stream->size() && _continueParsing; opNum++) { + for (uint32 opNum = 0; !stream.eos() && !stream.err() && stream.pos() < stream.size() && _continueParsing; opNum++) { // PICT v2 opcodes are two bytes - uint16 opcode = stream->readUint16BE(); + uint16 opcode = stream.readUint16BE(); if (opNum == 0 && opcode != 0x0011) error("Cannot find PICT version opcode"); @@ -238,7 +239,7 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale // Since opcodes are word-aligned, we need to mark our starting // position here. - uint32 startPos = stream->pos(); + uint32 startPos = stream.pos(); for (uint32 i = 0; i < _opcodes.size(); i++) { if (_opcodes[i].op == opcode) { @@ -252,76 +253,70 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale } // Align - stream->skip((stream->pos() - startPos) & 1); + stream.skip((stream.pos() - startPos) & 1); } - // If we got a palette throughout this nonsense, go and grab it - if (palette) - memcpy(palette, _palette, 256 * 3); - return _outputSurface; } -PictDecoder::PixMap PictDecoder::readPixMap(Common::SeekableReadStream *stream, bool hasBaseAddr) { +PICTDecoder::PixMap PICTDecoder::readPixMap(Common::SeekableReadStream &stream, bool hasBaseAddr) { PixMap pixMap; - pixMap.baseAddr = hasBaseAddr ? stream->readUint32BE() : 0; - pixMap.rowBytes = stream->readUint16BE() & 0x3fff; - pixMap.bounds.top = stream->readUint16BE(); - pixMap.bounds.left = stream->readUint16BE(); - pixMap.bounds.bottom = stream->readUint16BE(); - pixMap.bounds.right = stream->readUint16BE(); - pixMap.pmVersion = stream->readUint16BE(); - pixMap.packType = stream->readUint16BE(); - pixMap.packSize = stream->readUint32BE(); - pixMap.hRes = stream->readUint32BE(); - pixMap.vRes = stream->readUint32BE(); - pixMap.pixelType = stream->readUint16BE(); - pixMap.pixelSize = stream->readUint16BE(); - pixMap.cmpCount = stream->readUint16BE(); - pixMap.cmpSize = stream->readUint16BE(); - pixMap.planeBytes = stream->readUint32BE(); - pixMap.pmTable = stream->readUint32BE(); - pixMap.pmReserved = stream->readUint32BE(); + pixMap.baseAddr = hasBaseAddr ? stream.readUint32BE() : 0; + pixMap.rowBytes = stream.readUint16BE() & 0x3fff; + pixMap.bounds.top = stream.readUint16BE(); + pixMap.bounds.left = stream.readUint16BE(); + pixMap.bounds.bottom = stream.readUint16BE(); + pixMap.bounds.right = stream.readUint16BE(); + pixMap.pmVersion = stream.readUint16BE(); + pixMap.packType = stream.readUint16BE(); + pixMap.packSize = stream.readUint32BE(); + pixMap.hRes = stream.readUint32BE(); + pixMap.vRes = stream.readUint32BE(); + pixMap.pixelType = stream.readUint16BE(); + pixMap.pixelSize = stream.readUint16BE(); + pixMap.cmpCount = stream.readUint16BE(); + pixMap.cmpSize = stream.readUint16BE(); + pixMap.planeBytes = stream.readUint32BE(); + pixMap.pmTable = stream.readUint32BE(); + pixMap.pmReserved = stream.readUint32BE(); return pixMap; } struct PackBitsRectData { - PictDecoder::PixMap pixMap; + PICTDecoder::PixMap pixMap; Common::Rect srcRect; Common::Rect dstRect; uint16 mode; }; -void PictDecoder::unpackBitsRect(Common::SeekableReadStream *stream, bool hasPalette) { - static const PixelFormat directBitsFormat16 = PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); - +void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool hasPalette) { PackBitsRectData packBitsData; packBitsData.pixMap = readPixMap(stream, !hasPalette); // Read in the palette if there is one present if (hasPalette) { // See http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-267.html - stream->readUint32BE(); // seed - stream->readUint16BE(); // flags - uint16 colorCount = stream->readUint16BE() + 1; + stream.readUint32BE(); // seed + stream.readUint16BE(); // flags + uint16 colorCount = stream.readUint16BE() + 1; for (uint32 i = 0; i < colorCount; i++) { - stream->readUint16BE(); - _palette[i * 3] = stream->readUint16BE() >> 8; - _palette[i * 3 + 1] = stream->readUint16BE() >> 8; - _palette[i * 3 + 2] = stream->readUint16BE() >> 8; + stream.readUint16BE(); + _palette[i * 3] = stream.readUint16BE() >> 8; + _palette[i * 3 + 1] = stream.readUint16BE() >> 8; + _palette[i * 3 + 2] = stream.readUint16BE() >> 8; } } - packBitsData.srcRect.top = stream->readUint16BE(); - packBitsData.srcRect.left = stream->readUint16BE(); - packBitsData.srcRect.bottom = stream->readUint16BE(); - packBitsData.srcRect.right = stream->readUint16BE(); - packBitsData.dstRect.top = stream->readUint16BE(); - packBitsData.dstRect.left = stream->readUint16BE(); - packBitsData.dstRect.bottom = stream->readUint16BE(); - packBitsData.dstRect.right = stream->readUint16BE(); - packBitsData.mode = stream->readUint16BE(); + packBitsData.srcRect.top = stream.readUint16BE(); + packBitsData.srcRect.left = stream.readUint16BE(); + packBitsData.srcRect.bottom = stream.readUint16BE(); + packBitsData.srcRect.right = stream.readUint16BE(); + packBitsData.dstRect.top = stream.readUint16BE(); + packBitsData.dstRect.left = stream.readUint16BE(); + packBitsData.dstRect.bottom = stream.readUint16BE(); + packBitsData.dstRect.right = stream.readUint16BE(); + packBitsData.mode = stream.readUint16BE(); uint16 width = packBitsData.srcRect.width(); uint16 height = packBitsData.srcRect.height(); @@ -335,9 +330,6 @@ void PictDecoder::unpackBitsRect(Common::SeekableReadStream *stream, bool hasPal else bytesPerPixel = packBitsData.pixMap.pixelSize / 8; - _outputSurface = new Graphics::Surface(); - _outputSurface->create(width, height, (bytesPerPixel == 1) ? PixelFormat::createFormatCLUT8() : _pixelFormat); - // Ensure we have enough space in the buffer to hold an entire line's worth of pixels uint32 lineSize = MAX<int>(width * bytesPerPixel + (8 * 2 / packBitsData.pixMap.pixelSize), packBitsData.pixMap.rowBytes); byte *buffer = new byte[lineSize * height]; @@ -355,56 +347,48 @@ void PictDecoder::unpackBitsRect(Common::SeekableReadStream *stream, bool hasPal // TODO: Finish this. Hasn't been needed (yet). error("Unpacked DirectBitsRect data (not padded)"); } else if (packBitsData.pixMap.packType == 0 || packBitsData.pixMap.packType > 2) { // Packed - uint16 byteCount = (packBitsData.pixMap.rowBytes > 250) ? stream->readUint16BE() : stream->readByte(); - unpackBitsLine(buffer + i * _outputSurface->w * bytesPerPixel, packBitsData.pixMap.rowBytes, stream->readStream(byteCount), packBitsData.pixMap.pixelSize, bytesPerPixel); + uint16 byteCount = (packBitsData.pixMap.rowBytes > 250) ? stream.readUint16BE() : stream.readByte(); + unpackBitsLine(buffer + i * width * bytesPerPixel, packBitsData.pixMap.rowBytes, stream.readStream(byteCount), packBitsData.pixMap.pixelSize, bytesPerPixel); } } + _outputSurface = new Graphics::Surface(); + switch (bytesPerPixel) { case 1: // Just copy to the image + _outputSurface->create(width, height, PixelFormat::createFormatCLUT8()); memcpy(_outputSurface->pixels, buffer, _outputSurface->w * _outputSurface->h); break; case 2: // Convert from 16-bit to whatever surface we need - for (uint16 y = 0; y < _outputSurface->h; y++) { - for (uint16 x = 0; x < _outputSurface->w; x++) { - byte r = 0, g = 0, b = 0; - uint32 color = READ_BE_UINT16(buffer + (y * _outputSurface->w + x) * bytesPerPixel); - directBitsFormat16.colorToRGB(color, r, g, b); - if (_pixelFormat.bytesPerPixel == 2) - *((uint16 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); - else - *((uint32 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); - } - } + _outputSurface->create(width, height, PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); + for (uint16 y = 0; y < _outputSurface->h; y++) + for (uint16 x = 0; x < _outputSurface->w; x++) + WRITE_UINT16(_outputSurface->getBasePtr(x, y), READ_UINT16(buffer + (y * _outputSurface->w + x) * 2)); break; case 3: // Convert from 24-bit (planar!) to whatever surface we need + _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); for (uint16 y = 0; y < _outputSurface->h; y++) { for (uint16 x = 0; x < _outputSurface->w; x++) { byte r = *(buffer + y * _outputSurface->w * 3 + x); byte g = *(buffer + y * _outputSurface->w * 3 + _outputSurface->w + x); byte b = *(buffer + y * _outputSurface->w * 3 + _outputSurface->w * 2 + x); - if (_pixelFormat.bytesPerPixel == 2) - *((uint16 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); - else - *((uint32 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); + *((uint32 *)_outputSurface->getBasePtr(x, y)) = _outputSurface->format.RGBToColor(r, g, b); } } break; case 4: // Convert from 32-bit (planar!) to whatever surface we need + _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); for (uint16 y = 0; y < _outputSurface->h; y++) { for (uint16 x = 0; x < _outputSurface->w; x++) { byte r = *(buffer + y * _outputSurface->w * 4 + x); byte g = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w + x); byte b = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 2 + x); byte a = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 3 + x); - if (_pixelFormat.bytesPerPixel == 2) - *((uint16 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.ARGBToColor(r, g, b, a); - else - *((uint32 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.ARGBToColor(r, g, b, a); + *((uint32 *)_outputSurface->getBasePtr(x, y)) = _outputSurface->format.ARGBToColor(r, g, b, a); } } break; @@ -413,7 +397,7 @@ void PictDecoder::unpackBitsRect(Common::SeekableReadStream *stream, bool hasPal delete[] buffer; } -void PictDecoder::unpackBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bitsPerPixel, byte bytesPerPixel) { +void PICTDecoder::unpackBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bitsPerPixel, byte bytesPerPixel) { uint32 dataDecoded = 0; byte bytesPerDecode = (bytesPerPixel == 2) ? 2 : 1; @@ -426,7 +410,7 @@ void PictDecoder::unpackBitsLine(byte *out, uint32 length, Common::SeekableReadS for (uint32 i = 0; i < runSize; i++) { if (bytesPerDecode == 2) { - WRITE_BE_UINT16(out, value); + WRITE_UINT16(out, value); out += 2; } else { outputPixelBuffer(out, value, bitsPerPixel); @@ -434,12 +418,19 @@ void PictDecoder::unpackBitsLine(byte *out, uint32 length, Common::SeekableReadS } dataDecoded += runSize * bytesPerDecode; } else { - uint32 runSize = (op + 1) * bytesPerDecode; - - for (uint32 i = 0; i < runSize; i++) - outputPixelBuffer(out, data->readByte(), bitsPerPixel); + uint32 runSize = op + 1; + + if (bytesPerDecode == 1) { + for (uint32 i = 0; i < runSize; i++) + outputPixelBuffer(out, data->readByte(), bitsPerPixel); + } else { + for (uint32 i = 0; i < runSize; i++) { + WRITE_UINT16(out, data->readUint16BE()); + out += 2; + } + } - dataDecoded += runSize; + dataDecoded += runSize * bytesPerDecode; } } @@ -453,33 +444,52 @@ void PictDecoder::unpackBitsLine(byte *out, uint32 length, Common::SeekableReadS delete data; } -void PictDecoder::skipBitsRect(Common::SeekableReadStream *stream, bool hasPalette) { +void PICTDecoder::outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel) { + switch (bitsPerPixel) { + case 1: + for (int i = 7; i >= 0; i--) + *out++ = (value >> i) & 1; + break; + case 2: + for (int i = 6; i >= 0; i -= 2) + *out++ = (value >> i) & 3; + break; + case 4: + *out++ = (value >> 4) & 0xf; + *out++ = value & 0xf; + break; + default: + *out++ = value; + } +} + +void PICTDecoder::skipBitsRect(Common::SeekableReadStream &stream, bool hasPalette) { // Step through a PackBitsRect/DirectBitsRect function if (!hasPalette) - stream->readUint32BE(); + stream.readUint32BE(); - uint16 rowBytes = stream->readUint16BE(); - uint16 height = stream->readUint16BE(); - stream->readUint16BE(); - height = stream->readUint16BE() - height; - stream->readUint16BE(); + uint16 rowBytes = stream.readUint16BE(); + uint16 height = stream.readUint16BE(); + stream.readUint16BE(); + height = stream.readUint16BE() - height; + stream.readUint16BE(); uint16 packType; // Top two bits signify PixMap vs BitMap if (rowBytes & 0xC000) { // PixMap - stream->readUint16BE(); - packType = stream->readUint16BE(); - stream->skip(14); - stream->readUint16BE(); // pixelSize - stream->skip(16); + stream.readUint16BE(); + packType = stream.readUint16BE(); + stream.skip(14); + stream.readUint16BE(); // pixelSize + stream.skip(16); if (hasPalette) { - stream->readUint32BE(); - stream->readUint16BE(); - stream->skip((stream->readUint16BE() + 1) * 8); + stream.readUint32BE(); + stream.readUint16BE(); + stream.skip((stream.readUint16BE() + 1) * 8); } rowBytes &= 0x3FFF; @@ -488,85 +498,70 @@ void PictDecoder::skipBitsRect(Common::SeekableReadStream *stream, bool hasPalet packType = 0; } - stream->skip(18); + stream.skip(18); for (uint16 i = 0; i < height; i++) { if (packType == 1 || packType == 2 || rowBytes < 8) error("Unpacked PackBitsRect data"); else if (packType == 0 || packType > 2) - stream->skip((rowBytes > 250) ? stream->readUint16BE() : stream->readByte()); - } -} - -void PictDecoder::outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel) { - switch (bitsPerPixel) { - case 1: - for (int i = 7; i >= 0; i--) - *out++ = (value >> i) & 1; - break; - case 2: - for (int i = 6; i >= 0; i -= 2) - *out++ = (value >> i) & 3; - break; - case 4: - *out++ = (value >> 4) & 0xf; - *out++ = value & 0xf; - break; - default: - *out++ = value; + stream.skip((rowBytes > 250) ? stream.readUint16BE() : stream.readByte()); } } // Compressed QuickTime details can be found here: // http://developer.apple.com/legacy/mac/library/#documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/B-Chapter/2TheImageCompression.html // http://developer.apple.com/legacy/mac/library/#documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/F-Chapter/6WorkingwiththeImage.html - -void PictDecoder::decodeCompressedQuickTime(Common::SeekableReadStream *stream) { +void PICTDecoder::decodeCompressedQuickTime(Common::SeekableReadStream &stream) { // First, read all the fields from the opcode - uint32 dataSize = stream->readUint32BE(); - uint32 startPos = stream->pos(); + uint32 dataSize = stream.readUint32BE(); + uint32 startPos = stream.pos(); - /* uint16 version = */ stream->readUint16BE(); + /* uint16 version = */ stream.readUint16BE(); // Read in the display matrix uint32 matrix[3][3]; for (uint32 i = 0; i < 3; i++) for (uint32 j = 0; j < 3; j++) - matrix[i][j] = stream->readUint32BE(); + matrix[i][j] = stream.readUint32BE(); // We currently only support offseting images vertically from the matrix uint16 xOffset = 0; uint16 yOffset = matrix[2][1] >> 16; - uint32 matteSize = stream->readUint32BE(); - stream->skip(8); // matte rect - /* uint16 transferMode = */ stream->readUint16BE(); - stream->skip(8); // src rect - /* uint32 accuracy = */ stream->readUint32BE(); - uint32 maskSize = stream->readUint32BE(); + uint32 matteSize = stream.readUint32BE(); + stream.skip(8); // matte rect + /* uint16 transferMode = */ stream.readUint16BE(); + stream.skip(8); // src rect + /* uint32 accuracy = */ stream.readUint32BE(); + uint32 maskSize = stream.readUint32BE(); // Skip the matte and mask - stream->skip(matteSize + maskSize); + stream.skip(matteSize + maskSize); // Now we've reached the image descriptor, so read the relevant data from that - uint32 idStart = stream->pos(); - uint32 idSize = stream->readUint32BE(); - stream->skip(40); // miscellaneous stuff - uint32 jpegSize = stream->readUint32BE(); - stream->skip(idSize - (stream->pos() - idStart)); // more useless stuff + uint32 idStart = stream.pos(); + uint32 idSize = stream.readUint32BE(); + stream.skip(40); // miscellaneous stuff + uint32 jpegSize = stream.readUint32BE(); + stream.skip(idSize - (stream.pos() - idStart)); // more useless stuff - Common::SeekableReadStream *jpegStream = new Common::SeekableSubReadStream(stream, stream->pos(), stream->pos() + jpegSize); + Common::SeekableSubReadStream jpegStream(&stream, stream.pos(), stream.pos() + jpegSize); - if (!_jpeg->read(jpegStream)) - error("PictDecoder::decodeCompressedQuickTime(): Could not decode JPEG data"); + JPEGDecoder jpeg; + if (!jpeg.loadStream(jpegStream)) + error("PICTDecoder::decodeCompressedQuickTime(): Could not decode JPEG data"); - Graphics::Surface *jpegSurface = _jpeg->getSurface(_pixelFormat); + const Graphics::Surface *jpegSurface = jpeg.getSurface(); + + if (!_outputSurface) { + _outputSurface = new Graphics::Surface(); + _outputSurface->create(_imageRect.width(), _imageRect.height(), jpegSurface->format); + } for (uint16 y = 0; y < jpegSurface->h; y++) - memcpy(_outputSurface->getBasePtr(0 + xOffset, y + yOffset), jpegSurface->getBasePtr(0, y), jpegSurface->w * _pixelFormat.bytesPerPixel); + memcpy(_outputSurface->getBasePtr(0 + xOffset, y + yOffset), jpegSurface->getBasePtr(0, y), jpegSurface->w * jpegSurface->format.bytesPerPixel); - stream->seek(startPos + dataSize); - delete jpegStream; + stream.seek(startPos + dataSize); } } // End of namespace Graphics diff --git a/graphics/pict.h b/graphics/decoders/pict.h index b426c6ee35..b1e45a6bc1 100644 --- a/graphics/pict.h +++ b/graphics/decoders/pict.h @@ -27,6 +27,7 @@ #include "common/rect.h" #include "common/scummsys.h" +#include "graphics/decoders/image_decoder.h" #include "graphics/pixelformat.h" namespace Common { @@ -35,16 +36,20 @@ class SeekableReadStream; namespace Graphics { -class JPEG; struct Surface; -#define DECLARE_OPCODE(x) void x(Common::SeekableReadStream *stream) +#define DECLARE_OPCODE(x) void x(Common::SeekableReadStream &stream) -class PictDecoder { +class PICTDecoder : public ImageDecoder { public: - PictDecoder(Graphics::PixelFormat pixelFormat); - ~PictDecoder(); - Surface *decodeImage(Common::SeekableReadStream *stream, byte *palette = 0); + PICTDecoder(); + ~PICTDecoder(); + + // ImageDecoder API + bool loadStream(Common::SeekableReadStream &stream); + void destroy(); + const Surface *getSurface() const { return _outputSurface; } + const byte *getPalette() const { return _palette; } struct PixMap { uint32 baseAddr; @@ -64,26 +69,23 @@ public: uint32 pmReserved; }; - static PixMap readPixMap(Common::SeekableReadStream *stream, bool hasBaseAddr = true); + static PixMap readPixMap(Common::SeekableReadStream &stream, bool hasBaseAddr = true); private: Common::Rect _imageRect; - PixelFormat _pixelFormat; - JPEG *_jpeg; byte _palette[256 * 3]; - bool _isPaletted; Graphics::Surface *_outputSurface; bool _continueParsing; // Utility Functions - void unpackBitsRect(Common::SeekableReadStream *stream, bool hasPalette); - void unpackBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bitsPerPixel, byte bytesPerPixel); - void skipBitsRect(Common::SeekableReadStream *stream, bool hasPalette); - void decodeCompressedQuickTime(Common::SeekableReadStream *stream); + void unpackBitsRect(Common::SeekableReadStream &stream, bool hasPalette); + void unpackBitsLine(byte *out, uint32 length, Common::SeekableReadStream *stream, byte bitsPerPixel, byte bytesPerPixel); + void skipBitsRect(Common::SeekableReadStream &stream, bool hasPalette); + void decodeCompressedQuickTime(Common::SeekableReadStream &stream); void outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel); // Opcodes - typedef void (PictDecoder::*OpcodeProcPICT)(Common::SeekableReadStream *stream); + typedef void (PICTDecoder::*OpcodeProcPICT)(Common::SeekableReadStream &stream); struct PICTOpcode { PICTOpcode() { op = 0; proc = 0; desc = 0; } PICTOpcode(uint16 o, OpcodeProcPICT p, const char *d) { op = o; proc = p; desc = d; } diff --git a/graphics/png.cpp b/graphics/decoders/png.cpp index cea8b575ad..b87b6fdc7a 100644 --- a/graphics/png.cpp +++ b/graphics/decoders/png.cpp @@ -20,7 +20,7 @@ * */ -#include "graphics/png.h" +#include "graphics/decoders/png.h" #include "graphics/pixelformat.h" #include "graphics/surface.h" @@ -98,116 +98,30 @@ enum PNGFilters { kFilterPaeth = 4 }; -PNG::PNG() : _compressedBuffer(0), _compressedBufferSize(0), - _unfilteredSurface(0), _transparentColorSpecified(false) { +PNGDecoder::PNGDecoder() : _compressedBuffer(0), _compressedBufferSize(0), + _transparentColorSpecified(false), _outputSurface(0) { } -PNG::~PNG() { - if (_unfilteredSurface) { - _unfilteredSurface->free(); - delete _unfilteredSurface; - } +PNGDecoder::~PNGDecoder() { + destroy(); } -Graphics::Surface *PNG::getSurface(const PixelFormat &format) { - Graphics::Surface *output = new Graphics::Surface(); - output->create(_unfilteredSurface->w, _unfilteredSurface->h, format); - byte *src = (byte *)_unfilteredSurface->pixels; - byte a = 0xFF; - byte bpp = _unfilteredSurface->format.bytesPerPixel; - - if (_header.colorType != kIndexed) { - if (_header.colorType == kTrueColor || - _header.colorType == kTrueColorWithAlpha) { - if (bpp != 3 && bpp != 4) - error("Unsupported truecolor PNG format"); - } else if (_header.colorType == kGrayScale || - _header.colorType == kGrayScaleWithAlpha) { - if (bpp != 1 && bpp != 2) - error("Unsupported grayscale PNG format"); - } - - for (uint16 i = 0; i < output->h; i++) { - for (uint16 j = 0; j < output->w; j++) { - uint32 result = 0; - - switch (bpp) { - case 1: // Grayscale - if (_transparentColorSpecified) - a = (src[0] == _transparentColor[0]) ? 0 : 0xFF; - result = format.ARGBToColor( a, src[0], src[0], src[0]); - break; - case 2: // Grayscale + alpha - result = format.ARGBToColor(src[1], src[0], src[0], src[0]); - break; - case 3: // RGB - if (_transparentColorSpecified) { - bool isTransparentColor = (src[0] == _transparentColor[0] && - src[1] == _transparentColor[1] && - src[2] == _transparentColor[2]); - a = isTransparentColor ? 0 : 0xFF; - } - result = format.ARGBToColor( a, src[0], src[1], src[2]); - break; - case 4: // RGBA - result = format.ARGBToColor(src[3], src[0], src[1], src[2]); - break; - } - - if (format.bytesPerPixel == 2) // 2bpp - *((uint16 *)output->getBasePtr(j, i)) = (uint16)result; - else // 4bpp - *((uint32 *)output->getBasePtr(j, i)) = result; - - src += bpp; - } - } - } else { - byte index, r, g, b; - uint32 mask = (0xff >> (8 - _header.bitDepth)) << (8 - _header.bitDepth); - - // Convert the indexed surface to the target pixel format - for (uint16 i = 0; i < output->h; i++) { - int data = 0; - int bitCount = 8; - byte *src1 = src; - - for (uint16 j = 0; j < output->w; j++) { - if (bitCount == 8) { - data = *src; - src++; - } - - index = (data & mask) >> (8 - _header.bitDepth); - data = (data << _header.bitDepth) & 0xff; - bitCount -= _header.bitDepth; - - if (bitCount == 0) - bitCount = 8; - - r = _palette[index * 4 + 0]; - g = _palette[index * 4 + 1]; - b = _palette[index * 4 + 2]; - a = _palette[index * 4 + 3]; - - if (format.bytesPerPixel == 2) - *((uint16 *)output->getBasePtr(j, i)) = format.ARGBToColor(a, r, g, b); - else - *((uint32 *)output->getBasePtr(j, i)) = format.ARGBToColor(a, r, g, b); - } - src = src1 + output->w; - } +void PNGDecoder::destroy() { + if (_outputSurface) { + _outputSurface->free(); + delete _outputSurface; + _outputSurface = 0; } - - return output; } -bool PNG::read(Common::SeekableReadStream *str) { +bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { + destroy(); + uint32 chunkLength = 0, chunkType = 0; - _stream = str; + _stream = &stream; // First, check the PNG signature - if (_stream->readUint32BE() != MKTAG(0x89, 0x50, 0x4e, 0x47)) { + if (_stream->readUint32BE() != MKTAG(0x89, 'P', 'N', 'G')) { delete _stream; return false; } @@ -249,8 +163,10 @@ bool PNG::read(Common::SeekableReadStream *str) { error("A palette chunk has been found in a non-indexed PNG file"); if (chunkLength % 3 != 0) error("Palette chunk not divisible by 3"); + _paletteEntries = chunkLength / 3; - readPaletteChunk(); + _stream->read(_palette, _paletteEntries * 3); + memset(_paletteTransparency, 0xff, sizeof(_paletteTransparency)); break; case kChunkIEND: // End of stream @@ -269,7 +185,6 @@ bool PNG::read(Common::SeekableReadStream *str) { } // We no longer need the file stream, thus close it here - delete _stream; _stream = 0; // Unpack the compressed buffer @@ -295,7 +210,7 @@ bool PNG::read(Common::SeekableReadStream *str) { * Taken from lodePNG, with a slight patch: * http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx */ -byte PNG::paethPredictor(int16 a, int16 b, int16 c) { +byte PNGDecoder::paethPredictor(int16 a, int16 b, int16 c) { int16 pa = ABS<int16>(b - c); int16 pb = ABS<int16>(a - c); int16 pc = ABS<int16>(a + b - c - c); @@ -315,7 +230,7 @@ byte PNG::paethPredictor(int16 a, int16 b, int16 c) { * * Taken from lodePNG */ -void PNG::unfilterScanLine(byte *dest, const byte *scanLine, const byte *prevLine, uint16 byteWidth, byte filterType, uint16 length) { +void PNGDecoder::unfilterScanLine(byte *dest, const byte *scanLine, const byte *prevLine, uint16 byteWidth, byte filterType, uint16 length) { uint16 i; switch (filterType) { @@ -370,33 +285,29 @@ void PNG::unfilterScanLine(byte *dest, const byte *scanLine, const byte *prevLin } -void PNG::constructImage() { +int PNGDecoder::getBytesPerPixel() const { + return (getNumColorChannels() * _header.bitDepth + 7) / 8; +} + +void PNGDecoder::constructImage() { assert (_header.bitDepth != 0); - byte *dest; - byte *scanLine; - byte *prevLine = 0; - byte filterType; + int bytesPerPixel = getBytesPerPixel(); + int pitch = bytesPerPixel * _header.width; + byte *unfilteredSurface = new byte[pitch * _header.height]; + byte *dest = unfilteredSurface; uint16 scanLineWidth = (_header.width * getNumColorChannels() * _header.bitDepth + 7) / 8; - - if (_unfilteredSurface) { - _unfilteredSurface->free(); - delete _unfilteredSurface; - } - _unfilteredSurface = new Graphics::Surface(); - // TODO/FIXME: It seems we can not properly determine the format here. But maybe there is a way... - _unfilteredSurface->create(_header.width, _header.height, PixelFormat((getNumColorChannels() * _header.bitDepth + 7) / 8, 0, 0, 0, 0, 0, 0, 0, 0)); - scanLine = new byte[_unfilteredSurface->pitch]; - dest = (byte *)_unfilteredSurface->getBasePtr(0, 0); + byte *scanLine = new byte[scanLineWidth]; + byte *prevLine = 0; switch(_header.interlaceType) { case kNonInterlaced: - for (uint16 y = 0; y < _unfilteredSurface->h; y++) { - filterType = _imageData->readByte(); + for (uint16 y = 0; y < _header.height; y++) { + byte filterType = _imageData->readByte(); _imageData->read(scanLine, scanLineWidth); - unfilterScanLine(dest, scanLine, prevLine, _unfilteredSurface->format.bytesPerPixel, filterType, scanLineWidth); + unfilterScanLine(dest, scanLine, prevLine, bytesPerPixel, filterType, scanLineWidth); prevLine = dest; - dest += _unfilteredSurface->pitch; + dest += pitch; } break; case kInterlaced: @@ -409,9 +320,123 @@ void PNG::constructImage() { } delete[] scanLine; + + constructOutput(unfilteredSurface); + delete[] unfilteredSurface; } -void PNG::readHeaderChunk() { +Graphics::PixelFormat PNGDecoder::findPixelFormat() const { + // Try to find the best pixel format based on what we have here + // Which is basically 8bpp for paletted non-transparent + // and 32bpp for everything else + + switch (_header.colorType) { + case kIndexed: + if (!_transparentColorSpecified) + return Graphics::PixelFormat::createFormatCLUT8(); + // fall through + case kGrayScale: + case kTrueColor: + case kGrayScaleWithAlpha: + case kTrueColorWithAlpha: + // We'll go with standard RGBA 32-bit + return Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); + } + + error("Unknown PNG color type"); + return Graphics::PixelFormat(); +} + +void PNGDecoder::constructOutput(const byte *surface) { + _outputSurface = new Graphics::Surface(); + _outputSurface->create(_header.width, _header.height, findPixelFormat()); + + const byte *src = surface; + byte a = 0xFF; + int bytesPerPixel = getBytesPerPixel(); + + if (_header.colorType != kIndexed) { + if (_header.colorType == kTrueColor || + _header.colorType == kTrueColorWithAlpha) { + if (bytesPerPixel != 3 && bytesPerPixel != 4) + error("Unsupported truecolor PNG format"); + } else if (_header.colorType == kGrayScale || + _header.colorType == kGrayScaleWithAlpha) { + if (bytesPerPixel != 1 && bytesPerPixel != 2) + error("Unsupported grayscale PNG format"); + } + + for (uint16 i = 0; i < _outputSurface->h; i++) { + for (uint16 j = 0; j < _outputSurface->w; j++) { + uint32 result = 0; + + switch (bytesPerPixel) { + case 1: // Grayscale + if (_transparentColorSpecified) + a = (src[0] == _transparentColor[0]) ? 0 : 0xFF; + result = _outputSurface->format.ARGBToColor(a, src[0], src[0], src[0]); + break; + case 2: // Grayscale + alpha + result = _outputSurface->format.ARGBToColor(src[1], src[0], src[0], src[0]); + break; + case 3: // RGB + if (_transparentColorSpecified) { + bool isTransparentColor = (src[0] == _transparentColor[0] && + src[1] == _transparentColor[1] && + src[2] == _transparentColor[2]); + a = isTransparentColor ? 0 : 0xFF; + } + + result = _outputSurface->format.ARGBToColor(a, src[0], src[1], src[2]); + break; + case 4: // RGBA + result = _outputSurface->format.ARGBToColor(src[3], src[0], src[1], src[2]); + break; + } + + *((uint32 *)_outputSurface->getBasePtr(j, i)) = result; + src += bytesPerPixel; + } + } + } else { + uint32 mask = (0xff >> (8 - _header.bitDepth)) << (8 - _header.bitDepth); + + // Convert the indexed surface to the target pixel format + for (uint16 i = 0; i < _outputSurface->h; i++) { + int data = 0; + int bitCount = 8; + const byte *src1 = src; + + for (uint16 j = 0; j < _outputSurface->w; j++) { + if (bitCount == 8) { + data = *src; + src++; + } + + byte index = (data & mask) >> (8 - _header.bitDepth); + data = (data << _header.bitDepth) & 0xff; + bitCount -= _header.bitDepth; + + if (bitCount == 0) + bitCount = 8; + + if (_transparentColorSpecified) { + byte r = _palette[index * 3 + 0]; + byte g = _palette[index * 3 + 1]; + byte b = _palette[index * 3 + 2]; + a = _paletteTransparency[index]; + *((uint32 *)_outputSurface->getBasePtr(j, i)) = _outputSurface->format.ARGBToColor(a, r, g, b); + } else { + *((byte *)_outputSurface->getBasePtr(j, i)) = index; + } + } + + src = src1 + _outputSurface->w; + } + } +} + +void PNGDecoder::readHeaderChunk() { _header.width = _stream->readUint32BE(); _header.height = _stream->readUint32BE(); _header.bitDepth = _stream->readByte(); @@ -431,7 +456,7 @@ void PNG::readHeaderChunk() { _header.interlaceType = (PNGInterlaceType)_stream->readByte(); } -byte PNG::getNumColorChannels() { +byte PNGDecoder::getNumColorChannels() const { switch (_header.colorType) { case kGrayScale: return 1; // Gray @@ -448,16 +473,7 @@ byte PNG::getNumColorChannels() { } } -void PNG::readPaletteChunk() { - for (uint16 i = 0; i < _paletteEntries; i++) { - _palette[i * 4 + 0] = _stream->readByte(); // R - _palette[i * 4 + 1] = _stream->readByte(); // G - _palette[i * 4 + 2] = _stream->readByte(); // B - _palette[i * 4 + 3] = 0xFF; // Alpha, set in the tRNS chunk - } -} - -void PNG::readTransparencyChunk(uint32 chunkLength) { +void PNGDecoder::readTransparencyChunk(uint32 chunkLength) { _transparentColorSpecified = true; switch(_header.colorType) { @@ -472,8 +488,8 @@ void PNG::readTransparencyChunk(uint32 chunkLength) { _transparentColor[2] = _stream->readUint16BE(); break; case kIndexed: - for (uint32 i = 0; i < chunkLength; i++) - _palette[i * 4 + 3] = _stream->readByte(); + _stream->read(_paletteTransparency, chunkLength); + // A transparency chunk may have less entries // than the palette entries. The remaining ones // are unmodified (set to 255). Check here: diff --git a/graphics/png.h b/graphics/decoders/png.h index 078c76fc6b..1da0bea1ab 100644 --- a/graphics/png.h +++ b/graphics/decoders/png.h @@ -53,6 +53,7 @@ #include "common/scummsys.h" #include "common/textconsole.h" +#include "graphics/decoders/image_decoder.h" namespace Common { class SeekableReadStream; @@ -61,82 +62,44 @@ class SeekableReadStream; namespace Graphics { struct Surface; - -enum PNGColorType { - kGrayScale = 0, // bit depths: 1, 2, 4, 8, 16 - kTrueColor = 2, // bit depths: 8, 16 - kIndexed = 3, // bit depths: 1, 2, 4, 8 - kGrayScaleWithAlpha = 4, // bit depths: 8, 16 - kTrueColorWithAlpha = 6 // bit depths: 8, 16 -}; - -enum PNGInterlaceType { - kNonInterlaced = 0, - kInterlaced = 1 -}; - -struct PNGHeader { - uint32 width; - uint32 height; - byte bitDepth; - PNGColorType colorType; - byte compressionMethod; - byte filterMethod; - PNGInterlaceType interlaceType; -}; - struct PixelFormat; -class PNG { +class PNGDecoder : public ImageDecoder { public: - PNG(); - ~PNG(); - - /** - * Reads a PNG image from the specified stream - */ - bool read(Common::SeekableReadStream *str); - - /** - * Returns the information obtained from the PNG header. - */ - PNGHeader getHeader() const { return _header; } - - /** - * Returns the PNG image, formatted for the specified pixel format. - */ - Graphics::Surface *getSurface(const PixelFormat &format); - - /** - * Returns the indexed PNG8 image. Used for PNGs with an indexed 256 color - * palette, when they're shown on an 8-bit color screen, as no translation - * is taking place. - */ - Graphics::Surface *getIndexedSurface() { - if (_header.colorType != kIndexed) - error("Indexed surface requested for a non-indexed PNG"); - return _unfilteredSurface; - } - - /** - * Returns the palette of the specified PNG8 image, given a pointer to - * an RGBA palette array (4 x 256). - */ - void getPalette(byte *palette, uint16 &entries) { - if (_header.colorType != kIndexed) - error("Palette requested for a non-indexed PNG"); - for (int i = 0; i < 256; i++) { - palette[0 + i * 4] = _palette[0 + i * 4]; // R - palette[1 + i * 4] = _palette[1 + i * 4]; // G - palette[2 + i * 4] = _palette[2 + i * 4]; // B - palette[3 + i * 4] = _palette[3 + i * 4]; // A - } - entries = _paletteEntries; - } + PNGDecoder(); + ~PNGDecoder(); + + bool loadStream(Common::SeekableReadStream &stream); + void destroy(); + const Graphics::Surface *getSurface() const { return _outputSurface; } + const byte *getPalette() const { return _palette; } private: + enum PNGColorType { + kGrayScale = 0, // bit depths: 1, 2, 4, 8, 16 + kTrueColor = 2, // bit depths: 8, 16 + kIndexed = 3, // bit depths: 1, 2, 4, 8 + kGrayScaleWithAlpha = 4, // bit depths: 8, 16 + kTrueColorWithAlpha = 6 // bit depths: 8, 16 + }; + + enum PNGInterlaceType { + kNonInterlaced = 0, + kInterlaced = 1 + }; + + struct PNGHeader { + uint32 width; + uint32 height; + byte bitDepth; + PNGColorType colorType; + byte compressionMethod; + byte filterMethod; + PNGInterlaceType interlaceType; + }; + void readHeaderChunk(); - byte getNumColorChannels(); + byte getNumColorChannels() const; void readPaletteChunk(); void readTransparencyChunk(uint32 chunkLength); @@ -152,7 +115,8 @@ private: PNGHeader _header; - byte _palette[256 * 4]; // RGBA + byte _palette[256 * 3]; // RGB + byte _paletteTransparency[256]; uint16 _paletteEntries; uint16 _transparentColor[3]; bool _transparentColorSpecified; @@ -160,9 +124,12 @@ private: byte *_compressedBuffer; uint32 _compressedBufferSize; - Graphics::Surface *_unfilteredSurface; + Graphics::Surface *_outputSurface; + Graphics::PixelFormat findPixelFormat() const; + int getBytesPerPixel() const; + void constructOutput(const byte *surface); }; -} // End of Graphics namespace +} // End of namespace Graphics #endif // GRAPHICS_PNG_H diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp index 06231799ce..7505f7913e 100644 --- a/graphics/fonts/ttf.cpp +++ b/graphics/fonts/ttf.cpp @@ -338,7 +338,7 @@ void TTFFont::drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const return; if (y < 0) { - srcPos += y * glyph.image.pitch; + srcPos -= y * glyph.image.pitch; h += y; y = 0; } @@ -395,11 +395,11 @@ bool TTFFont::cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr) { FT_Glyph_Metrics &metrics = _face->glyph->metrics; - glyph.xOffset = ftFloor26_6(metrics.horiBearingX); + glyph.xOffset = _face->glyph->bitmap_left; int xMax = glyph.xOffset + ftCeil26_6(metrics.width); - glyph.yOffset = _ascent - ftFloor26_6(metrics.horiBearingY); + glyph.yOffset = _ascent - _face->glyph->bitmap_top; - glyph.advance = ftCeil26_6(metrics.horiAdvance); + glyph.advance = ftCeil26_6(_face->glyph->advance.x); // In case we got a negative xMin we adjust that, this might make some // characters make a bit odd, but it's the only way we can assure no 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..281f904b38 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -12,11 +12,7 @@ MODULE_OBJS := \ fonts/ttf.o \ fonts/winfont.o \ iff.o \ - imagedec.o \ - jpeg.o \ maccursor.o \ - pict.o \ - png.o \ primitives.o \ scaler.o \ scaler/thumbnail_intern.o \ @@ -26,7 +22,11 @@ MODULE_OBJS := \ VectorRenderer.o \ VectorRendererSpec.o \ wincursor.o \ - yuv_to_rgb.o + yuv_to_rgb.o \ + decoders/bmp.o \ + decoders/jpeg.o \ + decoders/pict.o \ + decoders/png.o ifdef USE_SCALERS MODULE_OBJS += \ diff --git a/graphics/surface.cpp b/graphics/surface.cpp index 79a7821feb..fcd702241a 100644 --- a/graphics/surface.cpp +++ b/graphics/surface.cpp @@ -20,6 +20,7 @@ */ #include "common/algorithm.h" +#include "common/endian.h" #include "common/util.h" #include "common/rect.h" #include "common/textconsole.h" @@ -270,4 +271,82 @@ void Surface::move(int dx, int dy, int height) { } } +Graphics::Surface *Surface::convertTo(const PixelFormat &dstFormat, const byte *palette) const { + assert(pixels); + + Graphics::Surface *surface = new Graphics::Surface(); + + // If the target format is the same, just copy + if (format == dstFormat) { + surface->copyFrom(*this); + return surface; + } + + if (format.bytesPerPixel == 0 || format.bytesPerPixel > 4) + error("Surface::convertTo(): Can only convert from 1Bpp, 2Bpp, 3Bpp, and 4Bpp"); + + if (dstFormat.bytesPerPixel != 2 && dstFormat.bytesPerPixel != 4) + error("Surface::convertTo(): Can only convert to 2Bpp and 4Bpp"); + + surface->create(w, h, dstFormat); + + if (format.bytesPerPixel == 1) { + // Converting from paletted to high color + assert(palette); + + for (int y = 0; y < h; y++) { + const byte *srcRow = (byte *)getBasePtr(0, y); + byte *dstRow = (byte *)surface->getBasePtr(0, y); + + for (int x = 0; x < w; x++) { + byte index = *srcRow++; + byte r = palette[index * 3]; + byte g = palette[index * 3 + 1]; + byte b = palette[index * 3 + 2]; + + uint32 color = dstFormat.RGBToColor(r, g, b); + + if (dstFormat.bytesPerPixel == 2) + *((uint16 *)dstRow) = color; + else + *((uint32 *)dstRow) = color; + + dstRow += dstFormat.bytesPerPixel; + } + } + } else { + // Converting from high color to high color + for (int y = 0; y < h; y++) { + const byte *srcRow = (byte *)getBasePtr(0, y); + byte *dstRow = (byte *)surface->getBasePtr(0, y); + + for (int x = 0; x < w; x++) { + uint32 srcColor; + if (format.bytesPerPixel == 2) + srcColor = READ_UINT16(srcRow); + else if (format.bytesPerPixel == 3) + srcColor = READ_UINT24(srcRow); + else + srcColor = READ_UINT32(srcRow); + + srcRow += format.bytesPerPixel; + + // Convert that color to the new format + byte r, g, b, a; + format.colorToARGB(srcColor, a, r, g, b); + uint32 color = dstFormat.ARGBToColor(a, r, g, b); + + if (dstFormat.bytesPerPixel == 2) + *((uint16 *)dstRow) = color; + else + *((uint32 *)dstRow) = color; + + dstRow += dstFormat.bytesPerPixel; + } + } + } + + return surface; +} + } // End of namespace Graphics diff --git a/graphics/surface.h b/graphics/surface.h index 018a283aad..eb8d1ac42e 100644 --- a/graphics/surface.h +++ b/graphics/surface.h @@ -135,6 +135,17 @@ struct Surface { void copyFrom(const Surface &surf); /** + * Convert the data to another pixel format. + * + * The calling code must call free on the returned surface and then delete + * it. + * + * @param dstFormat The desired format + * @param palette The palette (in RGB888), if the source format has a Bpp of 1 + */ + Graphics::Surface *convertTo(const PixelFormat &dstFormat, const byte *palette = 0) const; + + /** * Draw a line. * * @param x0 The x coordinate of the start point. diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp index feda48bf6d..ac7f217fee 100644 --- a/graphics/yuv_to_rgb.cpp +++ b/graphics/yuv_to_rgb.cpp @@ -199,6 +199,52 @@ namespace Graphics { *((PixelInt *)(d)) = (L[cr_r] | L[crb_g] | L[cb_b]) template<typename PixelInt> +void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { + // Keep the tables in pointers here to avoid a dereference on each pixel + const int16 *Cr_r_tab = lookup->_colorTab; + const int16 *Cr_g_tab = Cr_r_tab + 256; + const int16 *Cb_g_tab = Cr_g_tab + 256; + const int16 *Cb_b_tab = Cb_g_tab + 256; + const uint32 *rgbToPix = lookup->_rgbToPix; + + for (int h = 0; h < yHeight; h++) { + for (int w = 0; w < yWidth; w++) { + register const uint32 *L; + + int16 cr_r = Cr_r_tab[*vSrc]; + int16 crb_g = Cr_g_tab[*vSrc] + Cb_g_tab[*uSrc]; + int16 cb_b = Cb_b_tab[*uSrc]; + ++uSrc; + ++vSrc; + + PUT_PIXEL(*ySrc, dstPtr); + ySrc++; + dstPtr += sizeof(PixelInt); + } + + dstPtr += dstPitch - yWidth * sizeof(PixelInt); + ySrc += yPitch - yWidth; + uSrc += uvPitch - yWidth; + vSrc += uvPitch - yWidth; + } +} + +void convertYUV444ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { + // Sanity checks + assert(dst && dst->pixels); + assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); + assert(ySrc && uSrc && vSrc); + + const YUVToRGBLookup *lookup = YUVToRGBMan.getLookup(dst->format); + + // Use a templated function to avoid an if check on every pixel + if (dst->format.bytesPerPixel == 2) + convertYUV444ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + else + convertYUV444ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); +} + +template<typename PixelInt> void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { int halfHeight = yHeight >> 1; int halfWidth = yWidth >> 1; diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h index 259ba09810..8e025042dc 100644 --- a/graphics/yuv_to_rgb.h +++ b/graphics/yuv_to_rgb.h @@ -23,6 +23,7 @@ /** * @file * YUV to RGB conversion used in engines: + * - mohawk * - scumm (he) * - sword25 */ @@ -36,6 +37,20 @@ namespace Graphics { /** + * Convert a YUV444 image to an RGB surface + * + * @param dst the destination surface + * @param ySrc the source of the y component + * @param uSrc the source of the u component + * @param vSrc the source of the v component + * @param yWidth the width of the y surface + * @param yHeight the height of the y surface + * @param yPitch the pitch of the y surface + * @param uvPitch the pitch of the u and v surfaces + */ +void convertYUV444ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); + +/** * Convert a YUV420 image to an RGB surface * * @param dst the destination surface 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; diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat Binary files differindex d3a384ef77..c196db0e20 100644 --- a/gui/themes/translations.dat +++ b/gui/themes/translations.dat diff --git a/po/cs_CZ.po b/po/cs_CZ.po index feca25ee9c..9d786be555 100644 --- a/po/cs_CZ.po +++ b/po/cs_CZ.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: ScummVM 1.4.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" "POT-Creation-Date: 2012-03-07 22:09+0000\n" -"PO-Revision-Date: 2012-02-17 16:28+0100\n" +"PO-Revision-Date: 2012-03-17 19:07+0100\n" "Last-Translator: Zbynk Schwarz <zbynek.schwarz@gmail.com>\n" "Language-Team: \n" +"Language: Cesky\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-2\n" "Content-Transfer-Encoding: 8bit\n" -"Language: Cesky\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n" "X-Poedit-Language: Czech\n" "X-Poedit-Country: CZECH REPUBLIC\n" @@ -1160,14 +1160,13 @@ msgstr "" "dal pomoc." #: engines/dialogs.cpp:243 -#, fuzzy, c-format +#, c-format msgid "" "Gamestate save failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"Je nm lto, ale toto jdro v souasnosti nepodporuje hern npovdu. Prosm " -"prohldnte si README pro zkladn informace a pro instrukce jak zskat " -"dal pomoc." +"Uloen stavu hry selhalo (%s)! Prosm pette si dokumentaci pro zkladn " +"informace a pokyny k zskn dal podpory." #: engines/dialogs.cpp:321 engines/mohawk/dialogs.cpp:109 #: engines/mohawk/dialogs.cpp:174 @@ -1228,14 +1227,13 @@ msgstr "" "Pro podrobnosti si pette README." #: engines/engine.cpp:426 -#, fuzzy, c-format +#, c-format msgid "" "Gamestate load failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"Je nm lto, ale toto jdro v souasnosti nepodporuje hern npovdu. Prosm " -"prohldnte si README pro zkladn informace a pro instrukce jak zskat " -"dal pomoc." +"Naten stavu hry selhalo (%s)! Prosm pette si dokumentaci pro zkladn " +"informace a pokyny k zskn dal podpory." #: engines/engine.cpp:439 msgid "" @@ -2087,7 +2085,7 @@ msgstr "" #: engines/sword1/animation.cpp:539 #, c-format msgid "PSX stream cutscene '%s' cannot be played in paletted mode" -msgstr "" +msgstr "Proud videa PSX '%s' neme bt pehrn v reimu palety" #: engines/sword1/animation.cpp:560 engines/sword2/animation.cpp:455 msgid "DXA cutscenes found but ScummVM has been built without zlib support" @@ -2142,10 +2140,9 @@ msgid "This is the end of the Broken Sword 1 Demo" msgstr "Toto je konec Dema Broken Sword 1" #: engines/sword2/animation.cpp:435 -#, fuzzy msgid "" "PSX cutscenes found but ScummVM has been built without RGB color support" -msgstr "Videa DXA nalezena, ale ScummVM byl sestaven bez podpory zlib" +msgstr "Videa PSX nalezena, ale ScummVM byl sestaven bez podpory barev RGB" #: engines/parallaction/saveload.cpp:133 #, c-format @@ -2295,7 +2292,7 @@ msgstr "(Aktivn)" #: backends/keymapper/remap-dialog.cpp:106 msgid " (Blocked)" -msgstr "" +msgstr " (Blokovno)" #: backends/keymapper/remap-dialog.cpp:119 msgid " (Global)" @@ -76,6 +76,9 @@ endif ifneq ($(BACKEND), iphone) # Static libaries, used for the scummvm-static and iphone targets OSX_STATIC_LIBS := `$(STATICLIBPATH)/bin/sdl-config --static-libs` +ifdef USE_FREETYPE2 +OSX_STATIC_LIBS += $(STATICLIBPATH)/lib/libfreetype.a $(STATICLIBPATH)/lib/libbz2.a +endif endif ifdef USE_VORBIS @@ -147,7 +150,9 @@ osxsnap: bundle $(srcdir)/devtools/credits.pl --text > $(srcdir)/AUTHORS cp $(srcdir)/AUTHORS ./ScummVM-snapshot/Authors cp $(srcdir)/COPYING ./ScummVM-snapshot/License\ \(GPL\) + cp $(srcdir)/COPYING.BSD ./ScummVM-snapshot/License\ \(BSD\) cp $(srcdir)/COPYING.LGPL ./ScummVM-snapshot/License\ \(LGPL\) + cp $(srcdir)/COPYING.FREEFONT ./ScummVM-snapshot/License\ \(FREEFONT\) cp $(srcdir)/COPYRIGHT ./ScummVM-snapshot/Copyright\ Holders cp $(srcdir)/NEWS ./ScummVM-snapshot/News cp $(srcdir)/README ./ScummVM-snapshot/ScummVM\ ReadMe @@ -214,6 +219,7 @@ ifdef DIST_FILES_ENGINEDATA endif cp $(srcdir)/AUTHORS $(WIN32PATH)/AUTHORS.txt cp $(srcdir)/COPYING $(WIN32PATH)/COPYING.txt + cp $(srcdir)/COPYING.BSD $(WIN32PATH)/COPYING.BSD.txt cp $(srcdir)/COPYING.LGPL $(WIN32PATH)/COPYING.LGPL.txt cp $(srcdir)/COPYING.FREEFONT $(WIN32PATH)/COPYING.FREEFONT.txt cp $(srcdir)/COPYRIGHT $(WIN32PATH)/COPYRIGHT.txt diff --git a/video/codecs/mjpeg.cpp b/video/codecs/mjpeg.cpp index 248a80d714..10fd9d7c50 100644 --- a/video/codecs/mjpeg.cpp +++ b/video/codecs/mjpeg.cpp @@ -22,8 +22,8 @@ #include "common/system.h" #include "common/textconsole.h" -#include "graphics/jpeg.h" #include "graphics/surface.h" +#include "graphics/decoders/jpeg.h" #include "video/codecs/mjpeg.h" @@ -34,38 +34,31 @@ class SeekableReadStream; namespace Video { JPEGDecoder::JPEGDecoder() : Codec() { - _jpeg = new Graphics::JPEG(); _pixelFormat = g_system->getScreenFormat(); _surface = NULL; } JPEGDecoder::~JPEGDecoder() { - delete _jpeg; - if (_surface) { _surface->free(); delete _surface; } } -const Graphics::Surface *JPEGDecoder::decodeImage(Common::SeekableReadStream* stream) { - if (!_jpeg->read(stream)) { +const Graphics::Surface *JPEGDecoder::decodeImage(Common::SeekableReadStream *stream) { + Graphics::JPEGDecoder jpeg; + + if (!jpeg.loadStream(*stream)) { warning("Failed to decode JPEG frame"); return 0; } - if (!_surface) { - _surface = new Graphics::Surface(); - _surface->create(_jpeg->getWidth(), _jpeg->getHeight(), _pixelFormat); + if (_surface) { + _surface->free(); + delete _surface; } - Graphics::Surface *frame = _jpeg->getSurface(_pixelFormat); - assert(frame); - - _surface->copyFrom(*frame); - - frame->free(); - delete frame; + _surface = jpeg.getSurface()->convertTo(_pixelFormat); return _surface; } diff --git a/video/codecs/mjpeg.h b/video/codecs/mjpeg.h index 45cb57dea2..0c3b668a74 100644 --- a/video/codecs/mjpeg.h +++ b/video/codecs/mjpeg.h @@ -31,7 +31,7 @@ class SeekableReadStream; } namespace Graphics { -class JPEG; +struct Surface; } namespace Video { @@ -50,7 +50,6 @@ public: private: Graphics::PixelFormat _pixelFormat; - Graphics::JPEG *_jpeg; Graphics::Surface *_surface; }; |