mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-05 00:36:57 +00:00
Code to grab & downscale the screen content (used for thumbnail creation, part of patch #1163026)
svn-id: r17978
This commit is contained in:
parent
3279513b64
commit
9b8d88a113
@ -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 += \
|
||||
|
@ -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
|
||||
|
192
common/scaler/thumbnail.cpp
Normal file
192
common/scaler/thumbnail.cpp
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user