scummvm/graphics/scaler/sai.cpp
Eric Culp 4c967c5fbc GRAPHICS,SDL: Revision to scaler API
oldSrcScale() is now unified with scale(). Use enableSource(bool enable)
to switch functionality. Partial screen updates are also posible because
of this.

initialize() had its prototype changes although it is functionally the
same.

setSource() no longer has a type parameter, removing support for
multiple source surfaces. They weren't useful anyway.

useOldSrc() was renamed to useOldSource() to conform to the names of
other functions.
2021-03-15 16:48:40 +02:00

527 lines
16 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/sai.h"
#include "graphics/scaler/intern.h"
static inline int GetResult(uint32 A, uint32 B, uint32 C, uint32 D) {
const bool ac = (A==C);
const bool bc = (B==C);
const int x1 = ac;
const int y1 = (bc & !ac);
const bool ad = (A==D);
const bool bd = (B==D);
const int x2 = ad;
const int y2 = (bd & !ad);
const int x = x1+x2;
const int y = y1+y2;
return (y>>1) - (x>>1);
}
#define interpolate_1_1(a,b) (ColorMask::kBytesPerPixel == 2 ? interpolate16_1_1<ColorMask>(a,b) : interpolate32_1_1<ColorMask>(a,b))
#define interpolate_3_1(a,b) (ColorMask::kBytesPerPixel == 2 ? interpolate16_3_1<ColorMask>(a,b) : interpolate32_3_1<ColorMask>(a,b))
#define interpolate_6_1_1(a,b,c) (ColorMask::kBytesPerPixel == 2 ? interpolate16_6_1_1<ColorMask>(a,b,c) : interpolate32_6_1_1<ColorMask>(a,b,c))
#define interpolate_1_1_1_1(a,b,c,d) (ColorMask::kBytesPerPixel == 2 ? interpolate16_1_1_1_1<ColorMask>(a,b,c,d) : interpolate32_1_1_1_1<ColorMask>(a,b,c,d))
template<typename ColorMask, typename Pixel>
void Super2xSaITemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
const Pixel *bP;
Pixel *dP;
const uint32 nextlineSrc = srcPitch / sizeof(Pixel);
while (height--) {
bP = (const Pixel *)srcPtr;
dP = (Pixel *)dstPtr;
for (int i = 0; i < width; ++i) {
unsigned color4, color5, color6;
unsigned color1, color2, color3;
unsigned colorA0, colorA1, colorA2, colorA3;
unsigned colorB0, colorB1, colorB2, colorB3;
unsigned colorS1, colorS2;
unsigned product1a, product1b, product2a, product2b;
//--------------------------------------- B1 B2
// 4 5 6 S2
// 1 2 3 S1
// A1 A2
colorB0 = *(bP - nextlineSrc - 1);
colorB1 = *(bP - nextlineSrc);
colorB2 = *(bP - nextlineSrc + 1);
colorB3 = *(bP - nextlineSrc + 2);
color4 = *(bP - 1);
color5 = *(bP);
color6 = *(bP + 1);
colorS2 = *(bP + 2);
color1 = *(bP + nextlineSrc - 1);
color2 = *(bP + nextlineSrc);
color3 = *(bP + nextlineSrc + 1);
colorS1 = *(bP + nextlineSrc + 2);
colorA0 = *(bP + 2 * nextlineSrc - 1);
colorA1 = *(bP + 2 * nextlineSrc);
colorA2 = *(bP + 2 * nextlineSrc + 1);
colorA3 = *(bP + 2 * nextlineSrc + 2);
//--------------------------------------
if (color2 == color6 && color5 != color3) {
product2b = product1b = color2;
} else if (color5 == color3 && color2 != color6) {
product2b = product1b = color5;
} else if (color5 == color3 && color2 == color6) {
register int r = 0;
r += GetResult(color6, color5, color1, colorA1);
r += GetResult(color6, color5, color4, colorB1);
r += GetResult(color6, color5, colorA2, colorS1);
r += GetResult(color6, color5, colorB2, colorS2);
if (r > 0)
product2b = product1b = color6;
else if (r < 0)
product2b = product1b = color5;
else {
product2b = product1b = interpolate_1_1(color5, color6);
}
} else {
if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0)
product2b = interpolate_3_1(color3, color2);
else if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3)
product2b = interpolate_3_1(color2, color3);
else
product2b = interpolate_1_1(color2, color3);
if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0)
product1b = interpolate_3_1(color6, color5);
else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3)
product1b = interpolate_3_1(color5, color6);
else
product1b = interpolate_1_1(color5, color6);
}
if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2)
product2a = interpolate_1_1(color2, color5);
else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0)
product2a = interpolate_1_1(color2, color5);
else
product2a = color2;
if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2)
product1a = interpolate_1_1(color2, color5);
else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0)
product1a = interpolate_1_1(color2, color5);
else
product1a = color5;
*(dP + 0) = (Pixel) product1a;
*(dP + 1) = (Pixel) product1b;
*(dP + dstPitch / sizeof(Pixel) + 0) = (Pixel) product2a;
*(dP + dstPitch / sizeof(Pixel) + 1) = (Pixel) product2b;
bP += 1;
dP += 2;
}
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
}
}
template<typename ColorMask, typename Pixel>
void SuperEagleTemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
const Pixel *bP;
Pixel *dP;
const uint32 nextlineSrc = srcPitch / sizeof(Pixel);
while (height--) {
bP = (const Pixel *)srcPtr;
dP = (Pixel *)dstPtr;
for (int i = 0; i < width; ++i) {
unsigned color4, color5, color6;
unsigned color1, color2, color3;
unsigned colorA1, colorA2, colorB1, colorB2, colorS1, colorS2;
unsigned product1a, product1b, product2a, product2b;
colorB1 = *(bP - nextlineSrc);
colorB2 = *(bP - nextlineSrc + 1);
color4 = *(bP - 1);
color5 = *(bP);
color6 = *(bP + 1);
colorS2 = *(bP + 2);
color1 = *(bP + nextlineSrc - 1);
color2 = *(bP + nextlineSrc);
color3 = *(bP + nextlineSrc + 1);
colorS1 = *(bP + nextlineSrc + 2);
colorA1 = *(bP + 2 * nextlineSrc);
colorA2 = *(bP + 2 * nextlineSrc + 1);
// --------------------------------------
if (color5 != color3) {
if (color2 == color6) {
product1b = product2a = color2;
if ((color1 == color2) || (color6 == colorB2)) {
product1a = interpolate_3_1(color2, color5);
} else {
product1a = interpolate_1_1(color5, color6);
}
if ((color6 == colorS2) || (color2 == colorA1)) {
product2b = interpolate_3_1(color2, color3);
} else {
product2b = interpolate_1_1(color2, color3);
}
} else {
product2b = interpolate_6_1_1(color3, color2, color6);
product1a = interpolate_6_1_1(color5, color2, color6);
product2a = interpolate_6_1_1(color2, color5, color3);
product1b = interpolate_6_1_1(color6, color5, color3);
}
} else {
if (color2 != color6) {
product2b = product1a = color5;
if ((colorB1 == color5) || (color3 == colorS1)) {
product1b = interpolate_3_1(color5, color6);
} else {
product1b = interpolate_1_1(color5, color6);
}
if ((color3 == colorA2) || (color4 == color5)) {
product2a = interpolate_3_1(color5, color2);
} else {
product2a = interpolate_1_1(color2, color3);
}
} else {
register int r = 0;
r += GetResult(color6, color5, color1, colorA1);
r += GetResult(color6, color5, color4, colorB1);
r += GetResult(color6, color5, colorA2, colorS1);
r += GetResult(color6, color5, colorB2, colorS2);
if (r > 0) {
product1b = product2a = color2;
product1a = product2b = interpolate_1_1(color5, color6);
} else if (r < 0) {
product2b = product1a = color5;
product1b = product2a = interpolate_1_1(color5, color6);
} else {
product2b = product1a = color5;
product1b = product2a = color2;
}
}
}
*(dP + 0) = (Pixel) product1a;
*(dP + 1) = (Pixel) product1b;
*(dP + dstPitch / sizeof(Pixel) + 0) = (Pixel) product2a;
*(dP + dstPitch / sizeof(Pixel) + 1) = (Pixel) product2b;
bP += 1;
dP += 2;
}
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
}
}
template<typename ColorMask, typename Pixel>
void _2xSaITemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
const Pixel *bP;
Pixel *dP;
const uint32 nextlineSrc = srcPitch / sizeof(Pixel);
while (height--) {
bP = (const Pixel *)srcPtr;
dP = (Pixel *)dstPtr;
for (int i = 0; i < width; ++i) {
register unsigned colorA, colorB;
unsigned colorC, colorD,
colorE, colorF, colorG, colorH, colorI, colorJ, colorK, colorL, colorM, colorN, colorO;
unsigned product, product1, product2;
//---------------------------------------
// Map of the pixels: I|E F|J
// G|A B|K
// H|C D|L
// M|N O|P
colorI = *(bP - nextlineSrc - 1);
colorE = *(bP - nextlineSrc);
colorF = *(bP - nextlineSrc + 1);
colorJ = *(bP - nextlineSrc + 2);
colorG = *(bP - 1);
colorA = *(bP);
colorB = *(bP + 1);
colorK = *(bP + 2);
colorH = *(bP + nextlineSrc - 1);
colorC = *(bP + nextlineSrc);
colorD = *(bP + nextlineSrc + 1);
colorL = *(bP + nextlineSrc + 2);
colorM = *(bP + 2 * nextlineSrc - 1);
colorN = *(bP + 2 * nextlineSrc);
colorO = *(bP + 2 * nextlineSrc + 1);
if ((colorA == colorD) && (colorB != colorC)) {
if (((colorA == colorE) && (colorB == colorL)) ||
((colorA == colorC) && (colorA == colorF) && (colorB != colorE) && (colorB == colorJ))) {
product = colorA;
} else {
product = interpolate_1_1(colorA, colorB);
}
if (((colorA == colorG) && (colorC == colorO)) ||
((colorA == colorB) && (colorA == colorH) && (colorG != colorC) && (colorC == colorM))) {
product1 = colorA;
} else {
product1 = interpolate_1_1(colorA, colorC);
}
product2 = colorA;
} else if ((colorB == colorC) && (colorA != colorD)) {
if (((colorB == colorF) && (colorA == colorH)) ||
((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI))) {
product = colorB;
} else {
product = interpolate_1_1(colorA, colorB);
}
if (((colorC == colorH) && (colorA == colorF)) ||
((colorC == colorG) && (colorC == colorD) && (colorA != colorH) && (colorA == colorI))) {
product1 = colorC;
} else {
product1 = interpolate_1_1(colorA, colorC);
}
product2 = colorB;
} else if ((colorA == colorD) && (colorB == colorC)) {
if (colorA == colorB) {
product = colorA;
product1 = colorA;
product2 = colorA;
} else {
register int r = 0;
product1 = interpolate_1_1(colorA, colorC);
product = interpolate_1_1(colorA, colorB);
r += GetResult(colorA, colorB, colorG, colorE);
r -= GetResult(colorB, colorA, colorK, colorF);
r -= GetResult(colorB, colorA, colorH, colorN);
r += GetResult(colorA, colorB, colorL, colorO);
if (r > 0)
product2 = colorA;
else if (r < 0)
product2 = colorB;
else {
product2 = interpolate_1_1_1_1(colorA, colorB, colorC, colorD);
}
}
} else {
product2 = interpolate_1_1_1_1(colorA, colorB, colorC, colorD);
if ((colorA == colorC) && (colorA == colorF)
&& (colorB != colorE) && (colorB == colorJ)) {
product = colorA;
} else if ((colorB == colorE) && (colorB == colorD)
&& (colorA != colorF) && (colorA == colorI)) {
product = colorB;
} else {
product = interpolate_1_1(colorA, colorB);
}
if ((colorA == colorB) && (colorA == colorH)
&& (colorG != colorC) && (colorC == colorM)) {
product1 = colorA;
} else if ((colorC == colorG) && (colorC == colorD)
&& (colorA != colorH) && (colorA == colorI)) {
product1 = colorC;
} else {
product1 = interpolate_1_1(colorA, colorC);
}
}
*(dP + 0) = (Pixel) colorA;
*(dP + 1) = (Pixel) product;
*(dP + dstPitch / sizeof(Pixel) + 0) = (Pixel) product1;
*(dP + dstPitch / sizeof(Pixel) + 1) = (Pixel) product2;
bP += 1;
dP += 2;
}
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
}
}
// SAI
SAIPlugin::SAIPlugin() {
_factor = 2;
_factors.push_back(2);
}
void SAIPlugin::initialize(const Graphics::PixelFormat &format) {
_format = format;
}
void SAIPlugin::deinitialize() {
}
void SAIPlugin::scale(const uint8 *srcPtr, uint32 srcPitch,
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
if (_format.bytesPerPixel == 2) {
if (_format.gLoss == 2)
_2xSaITemplate<Graphics::ColorMasks<565>, uint16>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
else
_2xSaITemplate<Graphics::ColorMasks<555>, uint16>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
} else {
if (_format.aLoss == 0)
_2xSaITemplate<Graphics::ColorMasks<8888>, uint32>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
else
_2xSaITemplate<Graphics::ColorMasks<888>, uint32>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
}
}
uint SAIPlugin::increaseFactor() {
return _factor;
}
uint SAIPlugin::decreaseFactor() {
return _factor;
}
const char *SAIPlugin::getName() const {
return "sai";
}
const char *SAIPlugin::getPrettyName() const {
return "SAI";
}
REGISTER_PLUGIN_STATIC(SAI, PLUGIN_TYPE_SCALER, SAIPlugin);
// SuperSAI
SuperSAIPlugin::SuperSAIPlugin() {
_factor = 2;
_factors.push_back(2);
}
void SuperSAIPlugin::initialize(const Graphics::PixelFormat &format) {
_format = format;
}
void SuperSAIPlugin::deinitialize() {
}
void SuperSAIPlugin::scale(const uint8 *srcPtr, uint32 srcPitch,
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
if (_format.bytesPerPixel == 2) {
if (_format.gLoss == 2)
Super2xSaITemplate<Graphics::ColorMasks<565>, uint16>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
else
Super2xSaITemplate<Graphics::ColorMasks<555>, uint16>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
} else {
if (_format.aLoss == 0)
Super2xSaITemplate<Graphics::ColorMasks<8888>, uint32>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
else
Super2xSaITemplate<Graphics::ColorMasks<888>, uint32>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
}
}
uint SuperSAIPlugin::increaseFactor() {
return _factor;
}
uint SuperSAIPlugin::decreaseFactor() {
return _factor;
}
const char *SuperSAIPlugin::getName() const {
return "supersai";
}
const char *SuperSAIPlugin::getPrettyName() const {
return "SuperSAI";
}
REGISTER_PLUGIN_STATIC(SUPERSAI, PLUGIN_TYPE_SCALER, SuperSAIPlugin);
// SuperEagle
SuperEaglePlugin::SuperEaglePlugin() {
_factor = 2;
_factors.push_back(2);
}
void SuperEaglePlugin::initialize(const Graphics::PixelFormat &format) {
_format = format;
}
void SuperEaglePlugin::deinitialize() {
}
void SuperEaglePlugin::scale(const uint8 *srcPtr, uint32 srcPitch,
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
if (_format.bytesPerPixel == 2) {
if (_format.gLoss == 2)
SuperEagleTemplate<Graphics::ColorMasks<565>, uint16>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
else
SuperEagleTemplate<Graphics::ColorMasks<555>, uint16>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
} else {
if (_format.aLoss == 0)
SuperEagleTemplate<Graphics::ColorMasks<8888>, uint32>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
else
SuperEagleTemplate<Graphics::ColorMasks<888>, uint32>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
}
}
uint SuperEaglePlugin::increaseFactor() {
return _factor;
}
uint SuperEaglePlugin::decreaseFactor() {
return _factor;
}
const char *SuperEaglePlugin::getName() const {
return "supereagle";
}
const char *SuperEaglePlugin::getPrettyName() const {
return "SuperEagle";
}
REGISTER_PLUGIN_STATIC(SUPEREAGLE, PLUGIN_TYPE_SCALER, SuperEaglePlugin);