REminiscence/scaler.cpp

284 lines
6.0 KiB
C++
Raw Normal View History

2016-03-20 17:00:00 +01:00
/*
* REminiscence - Flashback interpreter
2019-10-27 17:00:00 +01:00
* Copyright (C) 2005-2019 Gregory Montoir (cyx@users.sourceforge.net)
2015-08-02 18:00:00 +02:00
*/
#include "scaler.h"
2016-03-20 17:00:00 +01:00
#include "util.h"
2015-08-02 18:00:00 +02:00
2018-03-18 17:00:00 +01:00
static void scanline2x(uint32_t *dst0, uint32_t *dst1, const uint32_t *src0, const uint32_t *src1, const uint32_t *src2, int w) {
uint32_t B, D, E, F, H;
// ABC
// DEF
// GHI
int x = 0;
// first pixel (D == E)
B = *(src0 + x);
E = *(src1 + x);
D = E;
F = *(src1 + x + 1);
H = *(src2 + x);
if (B != H && D != F) {
dst0[0] = D == B ? D : E;
dst0[1] = B == F ? F : E;
dst1[0] = D == H ? D : E;
dst1[1] = H == F ? F : E;
} else {
dst0[0] = E;
dst0[1] = E;
dst1[0] = E;
dst1[1] = E;
}
dst0 += 2;
dst1 += 2;
// center pixels
E = F;
for (x = 1; x < w - 1; ++x) {
B = *(src0 + x);
F = *(src1 + x + 1);
H = *(src2 + x);
if (B != H && D != F) {
dst0[0] = D == B ? D : E;
dst0[1] = B == F ? F : E;
dst1[0] = D == H ? D : E;
dst1[1] = H == F ? F : E;
} else {
dst0[0] = E;
dst0[1] = E;
dst1[0] = E;
dst1[1] = E;
}
D = E; E = F;
dst0 += 2;
dst1 += 2;
}
// last pixel (F == E)
B = *(src0 + x);
H = *(src2 + x);
if (B != H && D != F) {
dst0[0] = D == B ? D : E;
dst0[1] = B == F ? F : E;
dst1[0] = D == H ? D : E;
dst1[1] = H == F ? F : E;
} else {
dst0[0] = E;
dst0[1] = E;
dst1[0] = E;
dst1[1] = E;
}
}
2017-11-03 17:00:00 +01:00
static void scale2x(uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) {
2018-03-18 17:00:00 +01:00
assert(w > 1 && h > 1);
2015-08-02 18:00:00 +02:00
const int dstPitch2 = dstPitch * 2;
2018-03-18 17:00:00 +01:00
const uint32_t *src0, *src1, *src2;
// y == 0
src0 = src;
src1 = src;
src2 = src + srcPitch;
scanline2x(dst, dst + dstPitch, src0, src1, src2, w);
dst += dstPitch2;
// center
src0 = src;
src1 = src + srcPitch;
src2 = src + srcPitch * 2;
for (int y = 1; y < h - 1; ++y) {
scanline2x(dst, dst + dstPitch, src0, src1, src2, w);
2015-08-02 18:00:00 +02:00
dst += dstPitch2;
2018-03-18 17:00:00 +01:00
src0 += srcPitch;
src1 += srcPitch;
src2 += srcPitch;
}
// y == h-1
src2 = src1;
scanline2x(dst, dst + dstPitch, src0, src1, src2, w);
}
static void scanline3x(uint32_t *dst0, uint32_t *dst1, uint32_t *dst2, const uint32_t *src0, const uint32_t *src1, const uint32_t *src2, int w) {
uint32_t A, B, C, D, E, F, G, H, I;
// ABC
// DEF
// GHI
int x = 0;
// first pixel (A == B, D == E and G == H)
B = *(src0 + x);
A = B;
C = *(src0 + x + 1);
E = *(src1 + x);
D = E;
F = *(src1 + x + 1);
H = *(src2 + x);
G = H;
I = *(src2 + x + 1);
if (B != H && D != F) {
dst0[0] = D == B ? D : E;
dst0[1] = (E == B && E != C) || (B == F && E != A) ? B : E;
dst0[2] = B == F ? F : E;
dst1[0] = (D == B && E != G) || (D == B && E != A) ? D : E;
dst1[1] = E;
dst1[2] = (B == F && E != I) || (H == F && E != C) ? F : E;
dst2[0] = D == H ? D : E;
dst2[1] = (D == H && E != I) || (H == F && E != G) ? H : E;
dst2[2] = H == F ? F : E;
} else {
dst0[0] = E;
dst0[1] = E;
dst0[2] = E;
dst1[0] = E;
dst1[1] = E;
dst1[2] = E;
dst2[0] = E;
dst2[1] = E;
dst2[2] = E;
}
dst0 += 3;
dst1 += 3;
dst2 += 3;
// center pixels
B = C;
E = F;
H = I;
for (x = 1; x < w - 1; ++x) {
C = *(src0 + x + 1);
F = *(src1 + x + 1);
I = *(src2 + x + 1);
if (B != H && D != F) {
dst0[0] = D == B ? D : E;
dst0[1] = (E == B && E != C) || (B == F && E != A) ? B : E;
dst0[2] = B == F ? F : E;
dst1[0] = (D == B && E != G) || (D == B && E != A) ? D : E;
dst1[1] = E;
dst1[2] = (B == F && E != I) || (H == F && E != C) ? F : E;
dst2[0] = D == H ? D : E;
dst2[1] = (D == H && E != I) || (H == F && E != G) ? H : E;
dst2[2] = H == F ? F : E;
} else {
dst0[0] = E;
dst0[1] = E;
dst0[2] = E;
dst1[0] = E;
dst1[1] = E;
dst1[2] = E;
dst2[0] = E;
dst2[1] = E;
dst2[2] = E;
}
A = B; B = C;
D = E; E = F;
G = H; H = I;
dst0 += 3;
dst1 += 3;
dst2 += 3;
}
// last pixel (B == C, E == F and H == I)
if (B != H && D != F) {
dst0[0] = D == B ? D : E;
dst0[1] = (E == B && E != C) || (B == F && E != A) ? B : E;
dst0[2] = B == F ? F : E;
dst1[0] = (D == B && E != G) || (D == B && E != A) ? D : E;
dst1[1] = E;
dst1[2] = (B == F && E != I) || (H == F && E != C) ? F : E;
dst2[0] = D == H ? D : E;
dst2[1] = (D == H && E != I) || (H == F && E != G) ? H : E;
dst2[2] = H == F ? F : E;
} else {
dst0[0] = E;
dst0[1] = E;
dst0[2] = E;
dst1[0] = E;
dst1[1] = E;
dst1[2] = E;
dst2[0] = E;
dst2[1] = E;
dst2[2] = E;
2015-08-02 18:00:00 +02:00
}
}
2017-11-03 17:00:00 +01:00
static void scale3x(uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) {
2018-03-18 17:00:00 +01:00
assert(w > 1 && h > 1);
2015-08-02 18:00:00 +02:00
const int dstPitch2 = dstPitch * 2;
const int dstPitch3 = dstPitch * 3;
2018-03-18 17:00:00 +01:00
const uint32_t *src0, *src1, *src2;
// y == 0
src0 = src;
src1 = src;
src2 = src + srcPitch;
scanline3x(dst, dst + dstPitch, dst + dstPitch2, src0, src1, src2, w);
dst += dstPitch3;
// center
src0 = src;
src1 = src + srcPitch;
src2 = src + srcPitch * 2;
for (int y = 1; y < h - 1; ++y) {
scanline3x(dst, dst + dstPitch, dst + dstPitch2, src0, src1, src2, w);
2015-08-02 18:00:00 +02:00
dst += dstPitch3;
2018-03-18 17:00:00 +01:00
src0 += srcPitch;
src1 += srcPitch;
src2 += srcPitch;
2015-08-02 18:00:00 +02:00
}
2018-03-18 17:00:00 +01:00
// y == h-1
src2 = src1;
scanline3x(dst, dst + dstPitch, dst + dstPitch2, src0, src1, src2, w);
2015-08-02 18:00:00 +02:00
}
2017-11-03 17:00:00 +01:00
static void scale4x(uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) {
2015-08-02 18:00:00 +02:00
static struct {
2017-11-03 17:00:00 +01:00
uint32_t *ptr;
2015-08-02 18:00:00 +02:00
int w, h, pitch;
int size;
} buf;
2017-11-03 17:00:00 +01:00
const int size = (w * 2) * (h * 2) * sizeof(uint32_t);
2015-08-02 18:00:00 +02:00
if (buf.size < size) {
free(buf.ptr);
buf.size = size;
buf.w = w * 2;
buf.h = h * 2;
2017-11-03 17:00:00 +01:00
buf.pitch = buf.w;
buf.ptr = (uint32_t *)malloc(buf.size);
2015-08-02 18:00:00 +02:00
if (!buf.ptr) {
error("Unable to allocate scale4x intermediate buffer");
}
}
2017-11-03 17:00:00 +01:00
scale2x(buf.ptr, buf.pitch, src, srcPitch, w, h);
scale2x(dst, dstPitch, buf.ptr, buf.pitch, buf.w, buf.h);
}
static void scaleNx(int factor, uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) {
switch (factor) {
case 2:
return scale2x(dst, dstPitch, src, srcPitch, w, h);
case 3:
return scale3x(dst, dstPitch, src, srcPitch, w, h);
case 4:
return scale4x(dst, dstPitch, src, srcPitch, w, h);
}
2015-08-02 18:00:00 +02:00
}
2017-11-03 17:00:00 +01:00
const Scaler _internalScaler = {
SCALER_TAG,
"scaleNx",
2, 4,
scaleNx,
2015-08-02 18:00:00 +02:00
};