diff options
author | Johannes Schickel | 2008-08-20 14:03:34 +0000 |
---|---|---|
committer | Johannes Schickel | 2008-08-20 14:03:34 +0000 |
commit | f4fc8c3e4c1621e8c40392881a6c647f9915fa38 (patch) | |
tree | e4f8b46333677a458d790b511047d7a44b4abbc7 /graphics | |
parent | a79e9385a19530698e5c1cc1da39cb6b80cb9f74 (diff) | |
download | scummvm-rg350-f4fc8c3e4c1621e8c40392881a6c647f9915fa38.tar.gz scummvm-rg350-f4fc8c3e4c1621e8c40392881a6c647f9915fa38.tar.bz2 scummvm-rg350-f4fc8c3e4c1621e8c40392881a6c647f9915fa38.zip |
Committed patch #2050337 "KYRA/SCUMM: Thumbnail support/improvement". (Without Max' compressed backward seeking support for now)
svn-id: r34053
Diffstat (limited to 'graphics')
-rw-r--r-- | graphics/module.mk | 3 | ||||
-rw-r--r-- | graphics/scaler.h | 16 | ||||
-rw-r--r-- | graphics/scaler/thumbnail.cpp | 91 | ||||
-rw-r--r-- | graphics/thumbnail.cpp | 174 | ||||
-rw-r--r-- | graphics/thumbnail.h | 69 |
5 files changed, 316 insertions, 37 deletions
diff --git a/graphics/module.mk b/graphics/module.mk index 93e2db26c5..6fb2e89a82 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -16,7 +16,8 @@ MODULE_OBJS := \ primitives.o \ scaler.o \ scaler/thumbnail.o \ - surface.o + surface.o \ + thumbnail.o ifndef DISABLE_SCALERS MODULE_OBJS += \ diff --git a/graphics/scaler.h b/graphics/scaler.h index 2cf3f66239..95900de412 100644 --- a/graphics/scaler.h +++ b/graphics/scaler.h @@ -78,10 +78,22 @@ enum { extern void createThumbnail(const uint8* src, uint32 srcPitch, uint8* dstPtr, uint32 dstPitch, int width, int height); /** - * creates a thumbnail from the current screen (without overlay) + * Creates a thumbnail from the current screen (without overlay). + * * @param surf a surface (will always have 16 bpp after this for now) * @return false if a error occured */ -extern bool createThumbnailFromScreen(Graphics::Surface* surf); +extern bool createThumbnailFromScreen(Graphics::Surface *surf); + +/** + * Creates a thumbnail from a buffer. + * + * @param surf destination surface (will always have 16 bpp after this for now) + * @param pixels raw pixel data + * @param w width + * @param h height + * @param palette palette in RGB format + */ +extern bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette); #endif diff --git a/graphics/scaler/thumbnail.cpp b/graphics/scaler/thumbnail.cpp index f1caa5d2e5..bdfa0ff5f6 100644 --- a/graphics/scaler/thumbnail.cpp +++ b/graphics/scaler/thumbnail.cpp @@ -126,70 +126,93 @@ static bool grabScreen565(Graphics::Surface *surf) { return true; } -bool createThumbnailFromScreen(Graphics::Surface* surf) { - assert(surf); - - int screenWidth = g_system->getWidth(); - int screenHeight = g_system->getHeight(); - - Graphics::Surface screen; - - if (!grabScreen565(&screen)) - return false; +static bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) { + uint16 width = in.w; + uint16 inHeight = in.h; - uint16 width = screenWidth; - - if (screenWidth < 320) { + if (width < 320) { // Special case to handle MM NES (uses a screen width of 256) width = 320; // center MM NES screen Graphics::Surface newscreen; - newscreen.create(width, screen.h, screen.bytesPerPixel); + newscreen.create(width, in.h, in.bytesPerPixel); - uint8 *dst = (uint8*)newscreen.getBasePtr((320 - screenWidth) / 2, 0); - uint8 *src = (uint8*)screen.getBasePtr(0, 0); - uint16 height = screen.h; + uint8 *dst = (uint8*)newscreen.getBasePtr((320 - in.w) / 2, 0); + const uint8 *src = (uint8*)in.getBasePtr(0, 0); + uint16 height = in.h; while (height--) { - memcpy(dst, src, screen.pitch); + memcpy(dst, src, in.pitch); dst += newscreen.pitch; - src += screen.pitch; + src += in.pitch; } - screen.free(); - screen = newscreen; - } else if (screenWidth == 720) { + in.free(); + in = newscreen; + } else if (width == 720) { // Special case to handle Hercules mode width = 640; - screenHeight = 400; + inHeight = 400; // cut off menu and so on.. Graphics::Surface newscreen; - newscreen.create(width, 400, screen.bytesPerPixel); + newscreen.create(width, 400, in.bytesPerPixel); - uint8 *dst = (uint8*)newscreen.getBasePtr(0, (400 - 240) / 2); - uint8 *src = (uint8*)screen.getBasePtr(41, 28); + uint8 *dst = (uint8*)in.getBasePtr(0, (400 - 240) / 2); + const uint8 *src = (uint8*)in.getBasePtr(41, 28); for (int y = 0; y < 240; ++y) { - memcpy(dst, src, 640 * screen.bytesPerPixel); + memcpy(dst, src, 640 * in.bytesPerPixel); dst += newscreen.pitch; - src += screen.pitch; + src += in.pitch; } - screen.free(); - screen = newscreen; + in.free(); + in = newscreen; } - uint16 newHeight = !(screenHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1; + uint16 newHeight = !(inHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1; int gBitFormatBackUp = gBitFormat; gBitFormat = 565; - surf->create(kThumbnailWidth, newHeight, sizeof(uint16)); - createThumbnail((const uint8*)screen.pixels, width * sizeof(uint16), (uint8*)surf->pixels, surf->pitch, width, screenHeight); + out.create(kThumbnailWidth, newHeight, sizeof(uint16)); + createThumbnail((const uint8 *)in.pixels, width * sizeof(uint16), (uint8 *)out.pixels, out.pitch, width, inHeight); gBitFormat = gBitFormatBackUp; - screen.free(); + in.free(); return true; } + +bool createThumbnailFromScreen(Graphics::Surface* surf) { + assert(surf); + + Graphics::Surface screen; + + if (!grabScreen565(&screen)) + return false; + + return createThumbnail(*surf, screen); +} + +bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette) { + assert(surf); + + Graphics::Surface screen; + screen.create(w, h, 2); + + for (uint y = 0; y < screen.h; ++y) { + for (uint x = 0; x < screen.w; ++x) { + byte r, g, b; + r = palette[pixels[y * w + x] * 3]; + g = palette[pixels[y * w + x] * 3 + 1]; + b = palette[pixels[y * w + x] * 3 + 2]; + + ((uint16 *)screen.pixels)[y * screen.w + x] = RGBToColor<ColorMasks<565> >(r, g, b); + } + } + + return createThumbnail(*surf, screen); +} + diff --git a/graphics/thumbnail.cpp b/graphics/thumbnail.cpp new file mode 100644 index 0000000000..eb7dd3c6c1 --- /dev/null +++ b/graphics/thumbnail.cpp @@ -0,0 +1,174 @@ +/* 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. + * + * $URL$ + * $Id$ + */ + +#include "graphics/thumbnail.h" +#include "graphics/scaler.h" +#include "common/endian.h" +#include "common/system.h" + +namespace Graphics { + +namespace { +#define THMB_VERSION 1 + +struct ThumbnailHeader { + uint32 type; + uint32 size; + byte version; + uint16 width, height; + byte bpp; +}; + +#define ThumbnailHeaderSize (4+4+1+2+2+1) + +inline void colorToRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) { + r = (((color >> 11) & 0x1F) << 3); + g = (((color >> 5) & 0x3F) << 2); + b = ((color&0x1F) << 3); +} + +bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool outputWarnings) { + header.type = in.readUint32BE(); + // We also accept the bad 'BMHT' header here, for the sake of compatibility + // with some older savegames which were written incorrectly due to a bug in + // ScummVM which wrote the thumb header type incorrectly on LE systems. + if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT')) { + if (outputWarnings) + warning("couldn't find thumbnail header type"); + return false; + } + + header.size = in.readUint32BE(); + header.version = in.readByte(); + + if (header.version > THMB_VERSION) { + if (outputWarnings) + warning("trying to load a newer thumbnail version: %d instead of %d", header.version, THMB_VERSION); + return false; + } + + header.width = in.readUint16BE(); + header.height = in.readUint16BE(); + header.bpp = in.readByte(); + + return true; +} +} // end of anonymous namespace + +bool checkThumbnailHeader(Common::SeekableReadStream &in) { + uint32 position = in.pos(); + ThumbnailHeader header; + + bool hasHeader = loadHeader(in, header, false); + + in.seek(position, SEEK_SET); + + return hasHeader; +} + +bool skipThumbnailHeader(Common::SeekableReadStream &in) { + uint32 position = in.pos(); + ThumbnailHeader header; + + if (!loadHeader(in, header, true)) { + in.seek(position, SEEK_SET); + return false; + } + + in.seek(header.size - (in.pos() - position), SEEK_CUR); + return true; +} + +bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface &to) { + ThumbnailHeader header; + + if (!loadHeader(in, header, true)) + return false; + + if (header.bpp != 2) { + warning("trying to load thumbnail with unsupported bit depth %d", header.bpp); + return false; + } + + to.create(header.width, header.height, sizeof(OverlayColor)); + + OverlayColor *pixels = (OverlayColor *)to.pixels; + for (int y = 0; y < to.h; ++y) { + for (int x = 0; x < to.w; ++x) { + uint8 r, g, b; + colorToRGB(in.readUint16BE(), r, g, b); + + // converting to current OSystem Color + *pixels++ = g_system->RGBToColor(r, g, b); + } + } + + return true; +} + +bool saveThumbnail(Common::WriteStream &out) { + Graphics::Surface thumb; + + if (!createThumbnailFromScreen(&thumb)) { + warning("Couldn't create thumbnail from screen, aborting thumbnail save"); + return false; + } + + bool success = saveThumbnail(out, thumb); + thumb.free(); + + return success; +} + +bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb) { + if (thumb.bytesPerPixel != 2) { + warning("trying to save thumbnail with bpp different than 2"); + return false; + } + + ThumbnailHeader header; + header.type = MKID_BE('THMB'); + header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel; + header.version = THMB_VERSION; + header.width = thumb.w; + header.height = thumb.h; + header.bpp = thumb.bytesPerPixel; + + out.writeUint32BE(header.type); + out.writeUint32BE(header.size); + out.writeByte(header.version); + out.writeUint16BE(header.width); + out.writeUint16BE(header.height); + out.writeByte(header.bpp); + + // TODO: for later this shouldn't be casted to uint16... + uint16 *pixels = (uint16 *)thumb.pixels; + for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels) + out.writeUint16BE(*pixels); + + return true; +} + +} // end of namespace Graphics + diff --git a/graphics/thumbnail.h b/graphics/thumbnail.h new file mode 100644 index 0000000000..0553306519 --- /dev/null +++ b/graphics/thumbnail.h @@ -0,0 +1,69 @@ +/* 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. + * + * $URL$ + * $Id$ + */ + +#ifndef GRAPHICS_THUMBNAIL_H +#define GRAPHICS_THUMBNAIL_H + +#include "common/stream.h" +#include "graphics/surface.h" + +namespace Graphics { + +/** + * Checks for presence of the thumbnail save header. + * Seeks automatically back to start position after check. + * + * @param in stream to check for header + */ +bool checkThumbnailHeader(Common::SeekableReadStream &in); + +/** + * Skips a thumbnail header, if present. + * + * @param in stream to process + */ +bool skipThumbnailHeader(Common::SeekableReadStream &in); + +/** + * Lodas a thumbnail from the given input stream. + * The loaded thumbnail will be automatically converted to the + * current overlay pixelformat. + */ +bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface &to); + +/** + * Saves a thumbnail to the given write stream. + * Automatically creates a thumbnail from screen contents. + */ +bool saveThumbnail(Common::WriteStream &out); + +/** + * Saves a (given) thumbnail to the given write stream. + */ +bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb); + +} // end of namespace Graphics + +#endif + |