REminiscence/scaler.cpp

145 lines
3.8 KiB
C++

/*
* REminiscence - Flashback interpreter
* Copyright (C) 2005-2018 Gregory Montoir (cyx@users.sourceforge.net)
*/
#include "scaler.h"
#include "dynlib.h"
#include "util.h"
static void scale2x(uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) {
const int dstPitch2 = dstPitch * 2;
for (int y = 0; y < h; ++y) {
uint32_t *p = dst;
for (int x = 0; x < w; ++x, p += 2) {
const uint32_t E = *(src + x);
const uint32_t B = (y == 0) ? E : *(src + x - srcPitch);
const uint32_t D = (x == 0) ? E : *(src + x - 1);
const uint32_t F = (x == w - 1) ? E : *(src + x + 1);
const uint32_t H = (y == h - 1) ? E : *(src + x + 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;
}
}
dst += dstPitch2;
src += srcPitch;
}
}
static void scale3x(uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) {
const int dstPitch2 = dstPitch * 2;
const int dstPitch3 = dstPitch * 3;
for (int y = 0; y < h; ++y) {
uint32_t *p = dst;
for (int x = 0; x < w; ++x, p += 3) {
const uint32_t E = *(src + x);
const uint32_t B = (y == 0) ? E : *(src + x - srcPitch);
const uint32_t D = (x == 0) ? E : *(src + x - 1);
const uint32_t F = (x == w - 1) ? E : *(src + x + 1);
const uint32_t H = (y == h - 1) ? E : *(src + x + srcPitch);
uint32_t A, C;
if (y == 0) {
A = D;
C = F;
} else {
A = (x == 0) ? B : *(src + x - srcPitch - 1);
C = (x == w - 1) ? B : *(src + x - srcPitch + 1);
}
uint32_t G, I;
if (y == h - 1) {
G = D;
I = F;
} else {
G = (x == 0) ? H : *(src + x + srcPitch - 1);
I = (x == w - 1) ? H : *(src + x + 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;
}
}
dst += dstPitch3;
src += srcPitch;
}
}
static void scale4x(uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) {
static struct {
uint32_t *ptr;
int w, h, pitch;
int size;
} buf;
const int size = (w * 2) * (h * 2) * sizeof(uint32_t);
if (buf.size < size) {
free(buf.ptr);
buf.size = size;
buf.w = w * 2;
buf.h = h * 2;
buf.pitch = buf.w;
buf.ptr = (uint32_t *)malloc(buf.size);
if (!buf.ptr) {
error("Unable to allocate scale4x intermediate buffer");
}
}
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);
}
}
const Scaler _internalScaler = {
SCALER_TAG,
"scaleNx",
2, 4,
scaleNx,
};
static DynLib *dynLib;
static const char *kSoSym = "getScaler";
const Scaler *findScaler(const char *name) {
dynLib = new DynLib(name);
void *symbol = dynLib->getSymbol(kSoSym);
if (symbol) {
typedef const Scaler *(*GetScalerProc)();
return ((GetScalerProc)symbol)();
}
return 0;
}