2007-05-30 21:56:52 +00:00
|
|
|
/* 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.
|
2002-04-12 10:35:29 +00:00
|
|
|
*
|
|
|
|
* 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
|
2005-10-18 01:30:26 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2002-04-12 10:35:29 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2006-02-20 20:29:02 +00:00
|
|
|
#include "graphics/scaler/intern.h"
|
|
|
|
#include "graphics/scaler/scalebit.h"
|
2003-11-06 23:54:12 +00:00
|
|
|
#include "common/util.h"
|
2009-02-13 19:22:52 +00:00
|
|
|
#include "common/system.h"
|
2011-06-03 22:46:40 +00:00
|
|
|
#include "common/textconsole.h"
|
2003-09-21 12:10:32 +00:00
|
|
|
|
2003-09-29 16:02:47 +00:00
|
|
|
int gBitFormat = 565;
|
|
|
|
|
2010-05-09 11:00:17 +00:00
|
|
|
#ifdef USE_HQ_SCALERS
|
2003-09-29 16:02:47 +00:00
|
|
|
// RGB-to-YUV lookup table
|
2004-05-21 02:08:48 +00:00
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
#ifdef USE_NASM
|
|
|
|
// NOTE: if your compiler uses different mangled names, add another
|
|
|
|
// condition here
|
|
|
|
|
2008-03-23 11:24:23 +00:00
|
|
|
#if !defined(_WIN32) && !defined(MACOSX) && !defined(__OS2__)
|
2004-05-21 02:08:48 +00:00
|
|
|
#define RGBtoYUV _RGBtoYUV
|
2009-01-24 23:06:58 +00:00
|
|
|
#define hqx_highbits _hqx_highbits
|
|
|
|
#define hqx_lowbits _hqx_lowbits
|
2009-01-26 18:31:06 +00:00
|
|
|
#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
|
2004-05-21 02:08:48 +00:00
|
|
|
#endif
|
|
|
|
|
2009-01-24 23:06:58 +00:00
|
|
|
uint32 hqx_highbits = 0xF7DEF7DE;
|
|
|
|
uint32 hqx_lowbits = 0x0821;
|
2009-01-26 18:31:06 +00:00
|
|
|
uint32 hqx_low2bits = 0x0C63;
|
|
|
|
uint32 hqx_low3bits = 0x1CE7;
|
|
|
|
uint32 hqx_greenMask = 0;
|
|
|
|
uint32 hqx_redBlueMask = 0;
|
|
|
|
uint32 hqx_green_redBlue_Mask = 0;
|
2009-01-24 23:06:58 +00:00
|
|
|
|
2010-03-08 10:30:39 +00:00
|
|
|
#endif
|
|
|
|
|
2010-03-08 10:30:23 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2006-04-17 11:16:11 +00:00
|
|
|
uint32 *RGBtoYUV = 0;
|
2004-05-21 02:08:48 +00:00
|
|
|
}
|
2002-04-12 10:35:29 +00:00
|
|
|
|
2009-01-23 02:29:32 +00:00
|
|
|
void InitLUT(Graphics::PixelFormat format) {
|
|
|
|
uint8 r, g, b;
|
2003-09-29 16:02:47 +00:00
|
|
|
int Y, u, v;
|
2008-01-27 19:47:41 +00:00
|
|
|
|
2009-01-23 02:29:32 +00:00
|
|
|
assert(format.bytesPerPixel == 2);
|
2006-04-17 11:11:07 +00:00
|
|
|
|
2008-01-27 19:47:41 +00:00
|
|
|
// Allocate the YUV/LUT buffers on the fly if needed.
|
2006-04-17 11:16:11 +00:00
|
|
|
if (RGBtoYUV == 0)
|
|
|
|
RGBtoYUV = (uint32 *)malloc(65536 * sizeof(uint32));
|
|
|
|
|
2011-06-03 22:46:40 +00:00
|
|
|
if (!RGBtoYUV)
|
|
|
|
error("[InitLUT] Cannot allocate memory for YUV/LUT buffers");
|
|
|
|
|
2006-04-17 11:11:07 +00:00
|
|
|
for (int color = 0; color < 65536; ++color) {
|
2009-01-23 02:29:32 +00:00
|
|
|
format.colorToRGB(color, r, g, b);
|
2006-04-17 11:11:07 +00:00
|
|
|
Y = (r + g + b) >> 2;
|
|
|
|
u = 128 + ((r - b) >> 2);
|
|
|
|
v = 128 + ((-r + 2 * g - b) >> 3);
|
|
|
|
RGBtoYUV[color] = (Y << 16) | (u << 8) | v;
|
2004-05-21 02:08:48 +00:00
|
|
|
}
|
2009-01-26 18:31:06 +00:00
|
|
|
|
|
|
|
#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;
|
2009-05-24 15:17:42 +00:00
|
|
|
|
2009-01-26 18:31:06 +00:00
|
|
|
// 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);
|
2009-05-24 15:17:42 +00:00
|
|
|
|
2009-01-26 18:31:06 +00:00
|
|
|
hqx_green_redBlue_Mask = (hqx_greenMask << 16) | hqx_redBlueMask;
|
|
|
|
#endif
|
2006-04-17 11:11:07 +00:00
|
|
|
}
|
|
|
|
#endif
|
2004-05-21 02:08:48 +00:00
|
|
|
|
2002-04-12 10:35:29 +00:00
|
|
|
|
2009-02-13 19:22:52 +00:00
|
|
|
/** Lookup table for the DotMatrix scaler. */
|
|
|
|
uint16 g_dotmatrix[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
|
|
|
|
|
|
|
/** Init the scaler subsystem. */
|
2006-04-17 11:11:07 +00:00
|
|
|
void InitScalers(uint32 BitFormat) {
|
|
|
|
gBitFormat = BitFormat;
|
2009-01-24 23:06:58 +00:00
|
|
|
|
2009-02-13 19:22:52 +00:00
|
|
|
// FIXME: The pixelformat should be param to this function, not the bitformat.
|
|
|
|
// Until then, determine the pixelformat in other ways. Unfortunately,
|
|
|
|
// calling OSystem::getOverlayFormat() here might not be safe on all ports.
|
|
|
|
Graphics::PixelFormat format;
|
2009-01-24 23:06:58 +00:00
|
|
|
if (gBitFormat == 555) {
|
2009-02-13 19:22:52 +00:00
|
|
|
format = Graphics::createPixelFormat<555>();
|
|
|
|
} else if (gBitFormat == 565) {
|
|
|
|
format = Graphics::createPixelFormat<565>();
|
|
|
|
} else {
|
2009-02-14 18:16:21 +00:00
|
|
|
assert(g_system);
|
2009-02-13 19:22:52 +00:00
|
|
|
format = g_system->getOverlayFormat();
|
2009-01-24 23:06:58 +00:00
|
|
|
}
|
2009-02-13 19:22:52 +00:00
|
|
|
|
2010-05-09 11:00:17 +00:00
|
|
|
#ifdef USE_HQ_SCALERS
|
2009-02-13 19:22:52 +00:00
|
|
|
InitLUT(format);
|
2005-05-14 22:56:41 +00:00
|
|
|
#endif
|
2009-02-13 19:22:52 +00:00
|
|
|
|
|
|
|
// Build dotmatrix lookup table for the DotMatrix scaler.
|
|
|
|
g_dotmatrix[0] = g_dotmatrix[10] = format.RGBToColor(0, 63, 0);
|
|
|
|
g_dotmatrix[1] = g_dotmatrix[11] = format.RGBToColor(0, 0, 63);
|
|
|
|
g_dotmatrix[2] = g_dotmatrix[8] = format.RGBToColor(63, 0, 0);
|
|
|
|
g_dotmatrix[4] = g_dotmatrix[6] =
|
|
|
|
g_dotmatrix[12] = g_dotmatrix[14] = format.RGBToColor(63, 63, 63);
|
2005-05-14 23:28:22 +00:00
|
|
|
}
|
2006-04-17 11:11:07 +00:00
|
|
|
|
2013-01-24 19:15:13 +00:00
|
|
|
void DestroyScalers() {
|
2010-05-09 11:00:17 +00:00
|
|
|
#ifdef USE_HQ_SCALERS
|
2008-03-26 22:47:57 +00:00
|
|
|
free(RGBtoYUV);
|
|
|
|
RGBtoYUV = 0;
|
2008-03-27 11:06:29 +00:00
|
|
|
#endif
|
2008-03-26 19:29:33 +00:00
|
|
|
}
|
|
|
|
|
2002-04-12 10:35:29 +00:00
|
|
|
|
2003-09-29 16:02:47 +00:00
|
|
|
/**
|
|
|
|
* Trivial 'scaler' - in fact it doesn't do any scaling but just copies the
|
2009-02-14 18:16:21 +00:00
|
|
|
* source to the destination.
|
2003-09-29 16:02:47 +00:00
|
|
|
*/
|
|
|
|
void Normal1x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
|
|
|
int width, int height) {
|
2008-12-22 11:22:15 +00:00
|
|
|
// Spot the case when it can all be done in 1 hit
|
2012-06-12 02:13:00 +00:00
|
|
|
if ((srcPitch == sizeof(uint16) * (uint)width) && (dstPitch == sizeof(uint16) * (uint)width)) {
|
|
|
|
memcpy(dstPtr, srcPtr, sizeof(uint16) * width * height);
|
2009-02-13 19:22:52 +00:00
|
|
|
return;
|
2008-12-22 11:22:15 +00:00
|
|
|
}
|
2003-09-29 16:02:47 +00:00
|
|
|
while (height--) {
|
2012-06-12 02:13:00 +00:00
|
|
|
memcpy(dstPtr, srcPtr, sizeof(uint16) * width);
|
2003-05-25 22:01:19 +00:00
|
|
|
srcPtr += srcPitch;
|
2003-09-29 16:02:47 +00:00
|
|
|
dstPtr += dstPitch;
|
2003-06-10 16:25:49 +00:00
|
|
|
}
|
2002-04-12 10:35:29 +00:00
|
|
|
}
|
|
|
|
|
2010-05-09 11:00:17 +00:00
|
|
|
#ifdef USE_SCALERS
|
2010-01-25 01:39:44 +00:00
|
|
|
|
2009-07-27 16:29:36 +00:00
|
|
|
|
2010-03-08 10:31:42 +00:00
|
|
|
#ifdef USE_ARM_SCALER_ASM
|
2009-07-27 16:29:36 +00:00
|
|
|
extern "C" void Normal2xARM(const uint8 *srcPtr,
|
|
|
|
uint32 srcPitch,
|
|
|
|
uint8 *dstPtr,
|
|
|
|
uint32 dstPitch,
|
2009-07-27 17:04:06 +00:00
|
|
|
int width,
|
|
|
|
int height);
|
2009-07-27 16:29:36 +00:00
|
|
|
|
|
|
|
void Normal2x(const uint8 *srcPtr,
|
|
|
|
uint32 srcPitch,
|
|
|
|
uint8 *dstPtr,
|
|
|
|
uint32 dstPitch,
|
2009-07-27 17:04:06 +00:00
|
|
|
int width,
|
|
|
|
int height) {
|
2009-07-27 16:29:36 +00:00
|
|
|
Normal2xARM(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
|
|
|
}
|
2009-07-27 17:04:06 +00:00
|
|
|
|
2009-07-27 16:29:36 +00:00
|
|
|
#else
|
2003-09-29 16:02:47 +00:00
|
|
|
/**
|
2011-05-25 13:56:31 +00:00
|
|
|
* Trivial nearest-neighbor 2x scaler.
|
2003-09-29 16:02:47 +00:00
|
|
|
*/
|
|
|
|
void Normal2x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
|
|
|
int width, int height) {
|
|
|
|
uint8 *r;
|
2002-04-12 10:35:29 +00:00
|
|
|
|
2009-03-20 00:11:22 +00:00
|
|
|
assert(IS_ALIGNED(dstPtr, 4));
|
2003-05-25 22:01:19 +00:00
|
|
|
while (height--) {
|
2003-09-29 16:02:47 +00:00
|
|
|
r = dstPtr;
|
|
|
|
for (int i = 0; i < width; ++i, r += 4) {
|
2012-06-12 02:13:00 +00:00
|
|
|
uint32 color = *(((const uint16 *)srcPtr) + i);
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2004-08-08 15:45:58 +00:00
|
|
|
color |= color << 16;
|
2003-06-10 16:25:49 +00:00
|
|
|
|
2004-08-08 15:45:58 +00:00
|
|
|
*(uint32 *)(r) = color;
|
|
|
|
*(uint32 *)(r + dstPitch) = color;
|
2003-06-10 16:25:49 +00:00
|
|
|
}
|
2003-05-25 22:01:19 +00:00
|
|
|
srcPtr += srcPitch;
|
2003-09-29 16:02:47 +00:00
|
|
|
dstPtr += dstPitch << 1;
|
2003-06-10 16:25:49 +00:00
|
|
|
}
|
2002-04-12 10:35:29 +00:00
|
|
|
}
|
2009-07-27 16:29:36 +00:00
|
|
|
#endif
|
2002-04-12 10:35:29 +00:00
|
|
|
|
2003-09-29 16:02:47 +00:00
|
|
|
/**
|
2011-05-25 13:56:31 +00:00
|
|
|
* Trivial nearest-neighbor 3x scaler.
|
2003-09-29 16:02:47 +00:00
|
|
|
*/
|
|
|
|
void Normal3x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
|
|
|
int width, int height) {
|
|
|
|
uint8 *r;
|
2004-06-27 22:04:19 +00:00
|
|
|
const uint32 dstPitch2 = dstPitch * 2;
|
|
|
|
const uint32 dstPitch3 = dstPitch * 3;
|
2002-04-12 10:35:29 +00:00
|
|
|
|
2009-03-20 00:11:22 +00:00
|
|
|
assert(IS_ALIGNED(dstPtr, 2));
|
2003-05-25 22:01:19 +00:00
|
|
|
while (height--) {
|
2003-09-29 16:02:47 +00:00
|
|
|
r = dstPtr;
|
|
|
|
for (int i = 0; i < width; ++i, r += 6) {
|
|
|
|
uint16 color = *(((const uint16 *)srcPtr) + i);
|
2002-04-18 08:34:47 +00:00
|
|
|
|
2003-09-29 16:02:47 +00:00
|
|
|
*(uint16 *)(r + 0) = color;
|
|
|
|
*(uint16 *)(r + 2) = color;
|
|
|
|
*(uint16 *)(r + 4) = color;
|
|
|
|
*(uint16 *)(r + 0 + dstPitch) = color;
|
|
|
|
*(uint16 *)(r + 2 + dstPitch) = color;
|
|
|
|
*(uint16 *)(r + 4 + dstPitch) = color;
|
|
|
|
*(uint16 *)(r + 0 + dstPitch2) = color;
|
|
|
|
*(uint16 *)(r + 2 + dstPitch2) = color;
|
|
|
|
*(uint16 *)(r + 4 + dstPitch2) = color;
|
2003-06-10 16:25:49 +00:00
|
|
|
}
|
2003-05-25 22:01:19 +00:00
|
|
|
srcPtr += srcPitch;
|
2003-09-29 16:02:47 +00:00
|
|
|
dstPtr += dstPitch3;
|
2003-06-10 16:25:49 +00:00
|
|
|
}
|
2002-04-12 10:35:29 +00:00
|
|
|
}
|
|
|
|
|
2010-03-08 10:29:35 +00:00
|
|
|
#define interpolate_1_1 interpolate16_1_1<ColorMask>
|
|
|
|
#define interpolate_1_1_1_1 interpolate16_1_1_1_1<ColorMask>
|
2005-02-17 23:01:00 +00:00
|
|
|
|
|
|
|
/**
|
2011-05-25 13:56:31 +00:00
|
|
|
* Trivial nearest-neighbor 1.5x scaler.
|
2005-02-17 23:01:00 +00:00
|
|
|
*/
|
2010-03-08 10:29:35 +00:00
|
|
|
template<typename ColorMask>
|
2005-02-17 23:01:00 +00:00
|
|
|
void Normal1o5xTemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
|
|
|
int width, int height) {
|
|
|
|
uint8 *r;
|
|
|
|
const uint32 dstPitch2 = dstPitch * 2;
|
|
|
|
const uint32 dstPitch3 = dstPitch * 3;
|
|
|
|
const uint32 srcPitch2 = srcPitch * 2;
|
|
|
|
|
2009-03-20 00:12:45 +00:00
|
|
|
assert(IS_ALIGNED(dstPtr, 2));
|
2005-03-06 11:28:10 +00:00
|
|
|
while (height > 0) {
|
2005-02-17 23:01:00 +00:00
|
|
|
r = dstPtr;
|
|
|
|
for (int i = 0; i < width; i += 2, r += 6) {
|
|
|
|
uint16 color0 = *(((const uint16 *)srcPtr) + i);
|
|
|
|
uint16 color1 = *(((const uint16 *)srcPtr) + i + 1);
|
|
|
|
uint16 color2 = *(((const uint16 *)(srcPtr + srcPitch)) + i);
|
|
|
|
uint16 color3 = *(((const uint16 *)(srcPtr + srcPitch)) + i + 1);
|
|
|
|
|
|
|
|
*(uint16 *)(r + 0) = color0;
|
2009-01-27 01:46:29 +00:00
|
|
|
*(uint16 *)(r + 2) = interpolate_1_1(color0, color1);
|
2005-02-17 23:01:00 +00:00
|
|
|
*(uint16 *)(r + 4) = color1;
|
2009-01-27 01:46:29 +00:00
|
|
|
*(uint16 *)(r + 0 + dstPitch) = interpolate_1_1(color0, color2);
|
|
|
|
*(uint16 *)(r + 2 + dstPitch) = interpolate_1_1_1_1(color0, color1, color2, color3);
|
|
|
|
*(uint16 *)(r + 4 + dstPitch) = interpolate_1_1(color1, color3);
|
2005-02-17 23:01:00 +00:00
|
|
|
*(uint16 *)(r + 0 + dstPitch2) = color2;
|
2009-01-27 01:46:29 +00:00
|
|
|
*(uint16 *)(r + 2 + dstPitch2) = interpolate_1_1(color2, color3);
|
2005-02-17 23:01:00 +00:00
|
|
|
*(uint16 *)(r + 4 + dstPitch2) = color3;
|
|
|
|
}
|
|
|
|
srcPtr += srcPitch2;
|
|
|
|
dstPtr += dstPitch3;
|
|
|
|
height -= 2;
|
|
|
|
}
|
|
|
|
}
|
2010-03-08 10:30:23 +00:00
|
|
|
|
|
|
|
void Normal1o5x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
|
|
|
|
if (gBitFormat == 565)
|
|
|
|
Normal1o5xTemplate<Graphics::ColorMasks<565> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
|
|
|
else
|
|
|
|
Normal1o5xTemplate<Graphics::ColorMasks<555> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
|
|
|
}
|
2005-02-17 23:01:00 +00:00
|
|
|
|
2003-09-29 16:02:47 +00:00
|
|
|
/**
|
|
|
|
* The Scale2x filter, also known as AdvMame2x.
|
|
|
|
* See also http://scale2x.sourceforge.net
|
|
|
|
*/
|
2003-05-25 12:08:01 +00:00
|
|
|
void AdvMame2x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
2003-03-06 16:27:06 +00:00
|
|
|
int width, int height) {
|
2004-08-07 17:21:53 +00:00
|
|
|
scale(2, dstPtr, dstPitch, srcPtr - srcPitch, srcPitch, 2, width, height);
|
2002-04-24 07:42:29 +00:00
|
|
|
}
|
2002-05-04 00:05:45 +00:00
|
|
|
|
2003-09-29 16:02:47 +00:00
|
|
|
/**
|
|
|
|
* The Scale3x filter, also known as AdvMame3x.
|
|
|
|
* See also http://scale2x.sourceforge.net
|
|
|
|
*/
|
2003-05-25 12:08:01 +00:00
|
|
|
void AdvMame3x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
2003-05-09 22:44:16 +00:00
|
|
|
int width, int height) {
|
2004-08-07 17:21:53 +00:00
|
|
|
scale(3, dstPtr, dstPitch, srcPtr - srcPitch, srcPitch, 2, width, height);
|
2003-05-09 22:44:16 +00:00
|
|
|
}
|
|
|
|
|
2010-03-08 10:29:35 +00:00
|
|
|
template<typename ColorMask>
|
2005-07-30 21:11:48 +00:00
|
|
|
void TV2xTemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
2003-03-06 16:27:06 +00:00
|
|
|
int width, int height) {
|
2003-09-22 23:29:47 +00:00
|
|
|
const uint32 nextlineSrc = srcPitch / sizeof(uint16);
|
2003-05-25 12:08:01 +00:00
|
|
|
const uint16 *p = (const uint16 *)srcPtr;
|
2003-01-15 02:11:37 +00:00
|
|
|
|
2003-09-22 23:29:47 +00:00
|
|
|
const uint32 nextlineDst = dstPitch / sizeof(uint16);
|
2003-01-19 22:28:36 +00:00
|
|
|
uint16 *q = (uint16 *)dstPtr;
|
2003-01-15 02:11:37 +00:00
|
|
|
|
2003-09-29 16:02:47 +00:00
|
|
|
while (height--) {
|
2003-01-15 02:11:37 +00:00
|
|
|
for (int i = 0, j = 0; i < width; ++i, j += 2) {
|
2003-01-19 22:28:36 +00:00
|
|
|
uint16 p1 = *(p + i);
|
|
|
|
uint32 pi;
|
|
|
|
|
2010-03-08 10:29:35 +00:00
|
|
|
pi = (((p1 & ColorMask::kRedBlueMask) * 7) >> 3) & ColorMask::kRedBlueMask;
|
|
|
|
pi |= (((p1 & ColorMask::kGreenMask) * 7) >> 3) & ColorMask::kGreenMask;
|
2003-01-15 02:11:37 +00:00
|
|
|
|
|
|
|
*(q + j) = p1;
|
|
|
|
*(q + j + 1) = p1;
|
2003-01-19 22:28:36 +00:00
|
|
|
*(q + j + nextlineDst) = (uint16)pi;
|
|
|
|
*(q + j + nextlineDst + 1) = (uint16)pi;
|
2003-01-15 02:11:37 +00:00
|
|
|
}
|
|
|
|
p += nextlineSrc;
|
|
|
|
q += nextlineDst << 1;
|
|
|
|
}
|
|
|
|
}
|
2010-03-08 10:30:23 +00:00
|
|
|
|
|
|
|
void TV2x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
|
|
|
|
if (gBitFormat == 565)
|
|
|
|
TV2xTemplate<Graphics::ColorMasks<565> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
|
|
|
else
|
|
|
|
TV2xTemplate<Graphics::ColorMasks<555> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
|
|
|
}
|
2003-03-02 16:36:52 +00:00
|
|
|
|
2006-04-17 09:35:42 +00:00
|
|
|
static inline uint16 DOT_16(const uint16 *dotmatrix, uint16 c, int j, int i) {
|
2009-02-13 19:22:52 +00:00
|
|
|
return c - ((c >> 2) & dotmatrix[((j & 3) << 2) + (i & 3)]);
|
2003-03-02 16:36:52 +00:00
|
|
|
}
|
|
|
|
|
2009-02-13 19:22:52 +00:00
|
|
|
|
2003-10-24 17:14:56 +00:00
|
|
|
// FIXME: This scaler doesn't quite work. Either it needs to know where on the
|
|
|
|
// screen it's drawing, or the dirty rects will have to be adjusted so that
|
|
|
|
// access to the dotmatrix array are made in a consistent way. (Doing that in
|
|
|
|
// a way that also works together with aspect-ratio correction is left as an
|
|
|
|
// exercise for the reader.)
|
|
|
|
|
2003-05-25 12:08:01 +00:00
|
|
|
void DotMatrix(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
2003-11-08 22:43:46 +00:00
|
|
|
int width, int height) {
|
2006-04-17 09:35:42 +00:00
|
|
|
|
2009-02-13 19:22:52 +00:00
|
|
|
const uint16 *dotmatrix = g_dotmatrix;
|
2006-04-17 09:35:42 +00:00
|
|
|
|
2003-09-22 23:29:47 +00:00
|
|
|
const uint32 nextlineSrc = srcPitch / sizeof(uint16);
|
2003-05-25 12:08:01 +00:00
|
|
|
const uint16 *p = (const uint16 *)srcPtr;
|
2003-03-02 16:36:52 +00:00
|
|
|
|
2003-09-22 23:29:47 +00:00
|
|
|
const uint32 nextlineDst = dstPitch / sizeof(uint16);
|
2003-03-02 16:36:52 +00:00
|
|
|
uint16 *q = (uint16 *)dstPtr;
|
|
|
|
|
|
|
|
for (int j = 0, jj = 0; j < height; ++j, jj += 2) {
|
|
|
|
for (int i = 0, ii = 0; i < width; ++i, ii += 2) {
|
|
|
|
uint16 c = *(p + i);
|
2006-04-17 09:35:42 +00:00
|
|
|
*(q + ii) = DOT_16(dotmatrix, c, jj, ii);
|
|
|
|
*(q + ii + 1) = DOT_16(dotmatrix, c, jj, ii + 1);
|
|
|
|
*(q + ii + nextlineDst) = DOT_16(dotmatrix, c, jj + 1, ii);
|
|
|
|
*(q + ii + nextlineDst + 1) = DOT_16(dotmatrix, c, jj + 1, ii + 1);
|
2003-03-02 16:36:52 +00:00
|
|
|
}
|
|
|
|
p += nextlineSrc;
|
|
|
|
q += nextlineDst << 1;
|
|
|
|
}
|
|
|
|
}
|
2005-09-20 18:16:09 +00:00
|
|
|
|
2010-05-09 11:00:17 +00:00
|
|
|
#endif // #ifdef USE_SCALERS
|