scummvm/graphics/scaler/hq.cpp

161 lines
4.7 KiB
C++

/* 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/scaler/hq.h"
#include "graphics/scaler.h"
// RGB-to-YUV lookup table
extern "C" {
#ifdef USE_NASM
// NOTE: if your compiler uses different mangled names, add another
// condition here
#if !defined(_WIN32) && !defined(MACOSX) && !defined(__OS2__)
#define RGBtoYUV _RGBtoYUV
#define hqx_highbits _hqx_highbits
#define hqx_lowbits _hqx_lowbits
#define hqx_low2bits _hqx_low2bits
#define hqx_low3bits _hqx_low3bits
#define hqx_greenMask _hqx_greenMask
#define hqx_redBlueMask _hqx_redBlueMask
#define hqx_green_redBlue_Mask _hqx_green_redBlue_Mask
#endif
uint32 hqx_highbits = 0xF7DEF7DE;
uint32 hqx_lowbits = 0x0821;
uint32 hqx_low2bits = 0x0C63;
uint32 hqx_low3bits = 0x1CE7;
uint32 hqx_greenMask = 0;
uint32 hqx_redBlueMask = 0;
uint32 hqx_green_redBlue_Mask = 0;
#endif
/**
* 16bit RGB to YUV conversion table. This table is setup by InitLUT().
* Used by the hq scaler family.
*
* FIXME/TODO: The RGBtoYUV table sucks up 256 KB. This is bad.
* In addition we never free it...
*
* Note: a memory lookup table is *not* necessarily faster than computing
* these things on the fly, because of its size. The table together with
* the code, plus the input/output GFX data, may not fit in the cache on some
* systems, so main memory has to be accessed, which is about the worst thing
* that can happen to code which tries to be fast...
*
* So we should think about ways to get this smaller / removed. Maybe we can
* use the same technique employed by our MPEG code to reduce the size of the
* lookup table at the cost of some additional computations?
*
* Of course, the above is largely a conjecture, and the actual speed
* differences are likely to vary a lot between different architectures and
* CPUs.
*/
uint32 *RGBtoYUV = 0;
}
void InitLUT(Graphics::PixelFormat format) {
uint8 r, g, b;
int Y, u, v;
assert(format.bytesPerPixel == 2);
// Allocate the YUV/LUT buffers on the fly if needed.
if (RGBtoYUV == 0)
RGBtoYUV = (uint32 *)malloc(65536 * sizeof(uint32));
if (!RGBtoYUV)
error("[InitLUT] Cannot allocate memory for YUV/LUT buffers");
for (int color = 0; color < 65536; ++color) {
format.colorToRGB(color, r, g, b);
Y = (r + g + b) >> 2;
u = 128 + ((r - b) >> 2);
v = 128 + ((-r + 2 * g - b) >> 3);
RGBtoYUV[color] = (Y << 16) | (u << 8) | v;
}
#ifdef USE_NASM
hqx_lowbits = (1 << format.rShift) | (1 << format.gShift) | (1 << format.bShift),
hqx_low2bits = (3 << format.rShift) | (3 << format.gShift) | (3 << format.bShift),
hqx_low3bits = (7 << format.rShift) | (7 << format.gShift) | (7 << format.bShift),
hqx_highbits = format.RGBToColor(255,255,255) ^ hqx_lowbits;
// FIXME: The following code only does the right thing
// if the color order is RGB or BGR, i.e., green is in the middle.
hqx_greenMask = format.RGBToColor(0,255,0);
hqx_redBlueMask = format.RGBToColor(255,0,255);
hqx_green_redBlue_Mask = (hqx_greenMask << 16) | hqx_redBlueMask;
#endif
}
HQPlugin::HQPlugin() {
_factor = 2;
_factors.push_back(2);
_factors.push_back(3);
}
void HQPlugin::initialize(Graphics::PixelFormat format) {
InitLUT(format);
_format = format;
}
void HQPlugin::deinitialize() {
free(RGBtoYUV);
RGBtoYUV = 0;
}
void HQPlugin::scale(const uint8 *srcPtr, uint32 srcPitch,
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
switch (_factor) {
case 2:
HQ2x(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
break;
case 3:
HQ3x(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
break;
}
}
uint HQPlugin::increaseFactor() {
if (_factor < 3)
++_factor;
return _factor;
}
uint HQPlugin::decreaseFactor() {
if (_factor > 2)
--_factor;
return _factor;
}
const char *HQPlugin::getName() const {
return "hq";
}
const char *HQPlugin::getPrettyName() const {
return "HQ";
}
REGISTER_PLUGIN_STATIC(HQ, PLUGIN_TYPE_SCALER, HQPlugin);