193 lines
5.2 KiB
C++
193 lines
5.2 KiB
C++
|
/* REminiscence - Flashback interpreter
|
||
|
* Copyright (C) 2005-2015 Gregory Montoir
|
||
|
*
|
||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include "scaler.h"
|
||
|
|
||
|
|
||
|
static void point1x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) {
|
||
|
dstPitch >>= 1;
|
||
|
while (h--) {
|
||
|
memcpy(dst, src, w * 2);
|
||
|
dst += dstPitch;
|
||
|
src += srcPitch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void point2x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) {
|
||
|
dstPitch >>= 1;
|
||
|
const int dstPitch2 = dstPitch * 2;
|
||
|
while (h--) {
|
||
|
uint16_t *p = dst;
|
||
|
for (int i = 0; i < w; ++i, p += 2) {
|
||
|
const uint16_t c = *(src + i);
|
||
|
for (int j = 0; j < 2; ++j) {
|
||
|
*(p + j) = *(p + dstPitch + j) = c;
|
||
|
}
|
||
|
}
|
||
|
dst += dstPitch2;
|
||
|
src += srcPitch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void point3x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) {
|
||
|
dstPitch >>= 1;
|
||
|
const int dstPitch2 = dstPitch * 2;
|
||
|
const int dstPitch3 = dstPitch * 3;
|
||
|
while (h--) {
|
||
|
uint16_t *p = dst;
|
||
|
for (int i = 0; i < w; ++i, p += 3) {
|
||
|
const uint16_t c = *(src + i);
|
||
|
for (int j = 0; j < 3; ++j) {
|
||
|
*(p + j) = *(p + dstPitch + j) = *(p + dstPitch2 + j) = c;
|
||
|
}
|
||
|
}
|
||
|
dst += dstPitch3;
|
||
|
src += srcPitch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void point4x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) {
|
||
|
dstPitch >>= 1;
|
||
|
const int dstPitch2 = dstPitch * 2;
|
||
|
const int dstPitch3 = dstPitch * 3;
|
||
|
const int dstPitch4 = dstPitch * 4;
|
||
|
while (h--) {
|
||
|
uint16_t *p = dst;
|
||
|
for (int i = 0; i < w; ++i, p += 4) {
|
||
|
const uint16_t c = *(src + i);
|
||
|
for (int j = 0; j < 4; ++j) {
|
||
|
*(p + j) = *(p + dstPitch + j) = *(p + dstPitch2 + j) = *(p + dstPitch3 + j) = c;
|
||
|
}
|
||
|
}
|
||
|
dst += dstPitch4;
|
||
|
src += srcPitch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void scale2x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) {
|
||
|
dstPitch >>= 1;
|
||
|
const int dstPitch2 = dstPitch * 2;
|
||
|
while (h--) {
|
||
|
uint16_t *p = dst;
|
||
|
uint16_t D = *(src - 1);
|
||
|
uint16_t E = *(src);
|
||
|
for (int i = 0; i < w; ++i, p += 2) {
|
||
|
uint16_t B = *(src + i - srcPitch);
|
||
|
uint16_t F = *(src + i + 1);
|
||
|
uint16_t H = *(src + i + srcPitch);
|
||
|
if (B != H && D != F) {
|
||
|
*(p) = D == B ? D : E;
|
||
|
*(p + 1) = B == F ? F : E;
|
||
|
*(p + dstPitch) = D == H ? D : E;
|
||
|
*(p + dstPitch + 1) = H == F ? F : E;
|
||
|
} else {
|
||
|
*(p) = E;
|
||
|
*(p + 1) = E;
|
||
|
*(p + dstPitch) = E;
|
||
|
*(p + dstPitch + 1) = E;
|
||
|
}
|
||
|
D = E;
|
||
|
E = F;
|
||
|
}
|
||
|
dst += dstPitch2;
|
||
|
src += srcPitch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void scale3x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) {
|
||
|
dstPitch >>= 1;
|
||
|
const int dstPitch2 = dstPitch * 2;
|
||
|
const int dstPitch3 = dstPitch * 3;
|
||
|
while (h--) {
|
||
|
uint16_t *p = dst;
|
||
|
uint16_t A = *(src - srcPitch - 1);
|
||
|
uint16_t B = *(src - srcPitch);
|
||
|
uint16_t D = *(src - 1);
|
||
|
uint16_t E = *(src);
|
||
|
uint16_t G = *(src + srcPitch - 1);
|
||
|
uint16_t H = *(src + srcPitch);
|
||
|
for (int i = 0; i < w; ++i, p += 3) {
|
||
|
uint16_t C = *(src + i - srcPitch + 1);
|
||
|
uint16_t F = *(src + i + 1);
|
||
|
uint16_t I = *(src + i + srcPitch + 1);
|
||
|
if (B != H && D != F) {
|
||
|
*(p) = D == B ? D : E;
|
||
|
*(p + 1) = (D == B && E != C) || (B == F && E != A) ? B : E;
|
||
|
*(p + 2) = B == F ? F : E;
|
||
|
*(p + dstPitch) = (D == B && E != G) || (D == B && E != A) ? D : E;
|
||
|
*(p + dstPitch + 1) = E;
|
||
|
*(p + dstPitch + 2) = (B == F && E != I) || (H == F && E != C) ? F : E;
|
||
|
*(p + dstPitch2) = D == H ? D : E;
|
||
|
*(p + dstPitch2 + 1) = (D == H && E != I) || (H == F && E != G) ? H : E;
|
||
|
*(p + dstPitch2 + 2) = H == F ? F : E;
|
||
|
} else {
|
||
|
*(p) = E;
|
||
|
*(p + 1) = E;
|
||
|
*(p + 2) = E;
|
||
|
*(p + dstPitch) = E;
|
||
|
*(p + dstPitch + 1) = E;
|
||
|
*(p + dstPitch + 2) = E;
|
||
|
*(p + dstPitch2) = E;
|
||
|
*(p + dstPitch2 + 1) = E;
|
||
|
*(p + dstPitch2 + 2) = E;
|
||
|
}
|
||
|
A = B;
|
||
|
B = C;
|
||
|
D = E;
|
||
|
E = F;
|
||
|
G = H;
|
||
|
H = I;
|
||
|
}
|
||
|
dst += dstPitch3;
|
||
|
src += srcPitch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void scale4x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) {
|
||
|
static struct {
|
||
|
uint16_t *ptr;
|
||
|
int w, h, pitch;
|
||
|
int size;
|
||
|
} buf;
|
||
|
const int size = (w * 2 + 2) * (h * 2 + 2) * sizeof(uint16_t);
|
||
|
if (buf.size < size) {
|
||
|
free(buf.ptr);
|
||
|
buf.size = size;
|
||
|
buf.w = w * 2;
|
||
|
buf.h = h * 2;
|
||
|
buf.pitch = buf.w + 2;
|
||
|
buf.ptr = (uint16_t *)malloc(buf.size);
|
||
|
if (!buf.ptr) {
|
||
|
error("Unable to allocate scale4x intermediate buffer");
|
||
|
}
|
||
|
}
|
||
|
scale2x(buf.ptr + buf.pitch + 1, buf.pitch * sizeof(uint16_t), src, srcPitch, w, h);
|
||
|
scale2x(dst, dstPitch, buf.ptr + buf.pitch + 1, buf.pitch, w * 2, h * 2);
|
||
|
}
|
||
|
|
||
|
const Scaler _scalers[] = {
|
||
|
{ "point1x", &point1x, 1 },
|
||
|
{ "point2x", &point2x, 2 },
|
||
|
{ "scale2x", &scale2x, 2 },
|
||
|
{ "point3x", &point3x, 3 },
|
||
|
{ "scale3x", &scale3x, 3 },
|
||
|
{ "point4x", &point4x, 4 },
|
||
|
{ "scale4x", &scale4x, 4 },
|
||
|
{ 0, 0, 0 }
|
||
|
};
|
||
|
|