diff options
| -rw-r--r-- | common/module.mk | 3 | ||||
| -rw-r--r-- | common/scaler.h | 17 | ||||
| -rw-r--r-- | common/scaler/thumbnail.cpp | 192 | 
3 files changed, 211 insertions, 1 deletions
diff --git a/common/module.mk b/common/module.mk index 885264702b..83177bcfee 100644 --- a/common/module.mk +++ b/common/module.mk @@ -22,7 +22,8 @@ MODULE_OBJS += \  	common/scaler/hq3x.o \  	common/scaler/scale2x.o \  	common/scaler/scale3x.o \ -	common/scaler/scalebit.o +	common/scaler/scalebit.o \ +	common/scaler/thumbnail.o  ifdef HAVE_NASM  MODULE_OBJS += \ diff --git a/common/scaler.h b/common/scaler.h index 8460760bf6..37f7be99ff 100644 --- a/common/scaler.h +++ b/common/scaler.h @@ -23,6 +23,7 @@  #include "common/stdafx.h"  #include "common/scummsys.h" +#include "graphics/surface.h"  extern void InitScalers(uint32 BitFormat); @@ -59,5 +60,21 @@ extern void makeRectStretchable(int &x, int &y, int &w, int &h);  extern int stretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY); +// creates a 160x100 thumbnail for 320x200 games +// and 160x120 thumbnail for 320x240 and 640x480 games +// only 565 mode +enum { +	kThumbnailWidth = 160, +	kThumbnailHeight1 = 100, +	kThumbnailHeight2 = 120 +}; +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) + * @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);  #endif diff --git a/common/scaler/thumbnail.cpp b/common/scaler/thumbnail.cpp new file mode 100644 index 0000000000..6bca8e9f4a --- /dev/null +++ b/common/scaler/thumbnail.cpp @@ -0,0 +1,192 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001  Ludvig Strigeus + * Copyright (C) 2001-2005 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "common/scummsys.h" +#include "common/system.h" + +#include "scaler.h" +#include "scaler/intern.h" + +template<int bitFormat> +uint16 quadBlockInterpolate(const uint8* src, uint32 srcPitch) { +	uint16 colorx1y1 = *(((const uint16*)src)); +	uint16 colorx2y1 = *(((const uint16*)src) + 1); +	 +	uint16 colorx1y2 = *(((const uint16*)(src + srcPitch))); +	uint16 colorx2y2 = *(((const uint16*)(src + srcPitch)) + 1); +	 +	return Q_INTERPOLATE<bitFormat>(colorx1y1, colorx2y1, colorx1y2, colorx2y2);			 +} + +template<int bitFormat> +void createThumbnail_2(const uint8* src, uint32 srcPitch, uint8* dstPtr, uint32 dstPitch, int width, int height) { +	assert(width % 2 == 0); +	assert(height % 2 == 0); +	for (int y = 0; y < height; y += 2) { +		for (int x = 0; x < width; x += 2, dstPtr += 2) { +			*((uint16*)dstPtr) = quadBlockInterpolate<bitFormat>(src + 2 * x, srcPitch); +		} +		dstPtr += (dstPitch - 2 * width / 2); +		src += 2 * srcPitch; +	} +} + +template<int bitFormat> +void createThumbnail_4(const uint8* src, uint32 srcPitch, uint8* dstPtr, uint32 dstPitch, int width, int height) { +	assert(width % 4 == 0); +	assert(height % 4 == 0); +	for (int y = 0; y < height; y += 4) { +		for (int x = 0; x < width; x += 4, dstPtr += 2) { +			uint16 upleft = quadBlockInterpolate<bitFormat>(src + 2 * x, srcPitch); +			uint16 upright = quadBlockInterpolate<bitFormat>(src + 2 * (x + 2), srcPitch); +			uint16 downleft = quadBlockInterpolate<bitFormat>(src + srcPitch * 2 + 2 * x, srcPitch); +			uint16 downright = quadBlockInterpolate<bitFormat>(src + srcPitch * 2 + 2 * (x + 2), srcPitch); + +			*((uint16*)dstPtr) = Q_INTERPOLATE<bitFormat>(upleft, upright, downleft, downright);			 +		} +		dstPtr += (dstPitch - 2 * width / 4); +		src += 4 * srcPitch; +	} +} + +void createThumbnail(const uint8* src, uint32 srcPitch, uint8* dstPtr, uint32 dstPitch, int width, int height) { +	// only 1/2 and 1/4 downscale supported +	if (width != 320 && width != 640) +		return; +	 +	int downScaleMode = (width == 320) ? 2 : 4; +	 +	if (downScaleMode == 2) { +		if (gBitFormat == 565) +			createThumbnail_2<565>(src, srcPitch, dstPtr, dstPitch, width, height); +		else if (gBitFormat == 555) +			createThumbnail_2<555>(src, srcPitch, dstPtr, dstPitch, width, height); +	} else if (downScaleMode == 4) { +		if (gBitFormat == 565) +			createThumbnail_4<565>(src, srcPitch, dstPtr, dstPitch, width, height); +		else if (gBitFormat == 555) +			createThumbnail_4<555>(src, srcPitch, dstPtr, dstPitch, width, height); +	} +} + + +/** + * Copies the current screen contents to a new surface, using RGB565 format. + * WARNING: surf->free() must be called by the user to avoid leaking. + *  + * @param surf		the surfce to store the data in it + */ +static bool grabScreen565(Graphics::Surface *surf) { +	Graphics::Surface screen; +	if (!g_system->grabRawScreen(&screen)) +		return false; +	 +	assert(screen.bytesPerPixel == 1 && screen.pixels != 0); +	 +	byte palette[256 * 4]; +	g_system->grabPalette(&palette[0], 0, 256); +	 +	surf->create(screen.w, screen.h, 2); +	 +	for (uint y = 0; y < screen.h; ++y) { +		for (uint x = 0; x < screen.w; ++x) { +			byte r, g, b; +			r = palette[((uint8*)screen.pixels)[y * screen.pitch + x] * 4]; +			g = palette[((uint8*)screen.pixels)[y * screen.pitch + x] * 4 + 1]; +			b = palette[((uint8*)screen.pixels)[y * screen.pitch + x] * 4 + 2]; +			 +			((uint16*)surf->pixels)[y * surf->w + x] = (((r >> 3) & 0x1F) << 11) | (((g >> 2) & 0x3F) << 5) | ((b >> 3) & 0x1F); +		} +	} +	 +	screen.free(); +	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; + +	uint16 width = screenWidth; +	 +	if (screenWidth < 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); +		 +		uint8 *dst = (uint8*)newscreen.getBasePtr((320 - screenWidth) / 2, 0); +		uint8 *src = (uint8*)screen.getBasePtr(0, 0); +		uint16 height = screen.h; +		 +		while (height--) { +			memcpy(dst, src, screen.pitch); +			dst += newscreen.pitch; +			src += screen.pitch; +		} +		 +		screen.free(); +		screen = newscreen; +	} else if (screenWidth == 720) { +		// Special case to handle Hercules mode +		width = 640; +		screenHeight = 400; +		 +		// cut off menu and so on.. +		Graphics::Surface newscreen; +		newscreen.create(width, 400, screen.bytesPerPixel); + +		uint8 *dst = (uint8*)newscreen.getBasePtr(0, (400 - 240) / 2); +		uint8 *src = (uint8*)screen.getBasePtr(41, 28); + +		for (int y = 0; y < 240; ++y) { +			memcpy(dst, src, 640 * screen.bytesPerPixel); +			dst += newscreen.pitch; +			src += screen.pitch; +		} + +		screen.free(); +		screen = newscreen; +	} +	 +	uint16 newHeight = !(screenHeight % 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);	 +	gBitFormat = gBitFormatBackUp; +	 +	screen.free(); +	 +	return true; +}  | 
