Templatize bilinear up/down scaler

This commit is contained in:
Elias Batek 2025-01-28 02:29:45 +01:00
parent 7f91abfc0a
commit 31308e0777
1 changed files with 294 additions and 263 deletions

View File

@ -3019,13 +3019,7 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
// ==== Bilinear ==== // ==== Bilinear ====
static if ((filter == ScalingFilter.bilinear) || (filter == ScalingFilter.fauxLinear)) { static if ((filter == ScalingFilter.bilinear) || (filter == ScalingFilter.fauxLinear)) {
const Size delta = (target.size - source.size); void scaleToLinearImpl(ScalingDirection directionX, ScalingDirection directionY)() {
const ScalingDirection[2] directions = [
scalingDirectionFromDelta(delta.width),
scalingDirectionFromDelta(delta.height),
];
auto dst = PixmapScannerRW(target); auto dst = PixmapScannerRW(target);
size_t y = 0; size_t y = 0;
@ -3040,17 +3034,17 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
const int[2] posSrcX = () { const int[2] posSrcX = () {
int[2] result; int[2] result;
if (directions[idxX] == none) { static if (directionX == none) {
result = [ result = [
posSrc[idxX].castTo!int, posSrc[idxX].castTo!int,
posSrc[idxX].castTo!int, posSrc[idxX].castTo!int,
]; ];
} else if (directions[idxX] == up) { } else static if (directionX == up) {
result = [ result = [
min(sourceMaxX, posSrc[idxX].floor().castTo!int), min(sourceMaxX, posSrc[idxX].floor().castTo!int),
min(sourceMaxX, posSrc[idxX].ceil().castTo!int), min(sourceMaxX, posSrc[idxX].ceil().castTo!int),
]; ];
} else /* if (directions[0] == down) */ { } else /* if (directionX == down) */ {
const ratioXHalf = (ratios[idxX] >> 1); const ratioXHalf = (ratios[idxX] >> 1);
result = [ result = [
max((posSrc[idxX] - ratioXHalf).roundEven().castTo!int, 0), max((posSrc[idxX] - ratioXHalf).roundEven().castTo!int, 0),
@ -3062,17 +3056,17 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
const int[2] posSrcY = () { const int[2] posSrcY = () {
int[2] result; int[2] result;
if (directions[idxY] == none) { static if (directionY == none) {
result = [ result = [
posSrc[idxY].castTo!int, posSrc[idxY].castTo!int,
posSrc[idxY].castTo!int, posSrc[idxY].castTo!int,
]; ];
} else if (directions[idxY] == up) { } else static if (directionY == up) {
result = [ result = [
min(sourceMaxY, posSrc[idxY].floor().castTo!int), min(sourceMaxY, posSrc[idxY].floor().castTo!int),
min(sourceMaxY, posSrc[idxY].ceil().castTo!int), min(sourceMaxY, posSrc[idxY].ceil().castTo!int),
]; ];
} else /* if (directions[idxY] == down) */ { } else /* if (directionY == down) */ {
const ratioHalf = (ratios[idxY] >> 1); const ratioHalf = (ratios[idxY] >> 1);
result = [ result = [
max((posSrc[idxY] - ratioHalf).roundEven().castTo!int, 0), max((posSrc[idxY] - ratioHalf).roundEven().castTo!int, 0),
@ -3121,9 +3115,9 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
ulong sampleX() { ulong sampleX() {
pragma(inline, true); pragma(inline, true);
if (directions[0] == none) { static if (directionX == none) {
return (() @trusted => pxNeighs[idxTL].components.ptr[ib])(); return (() @trusted => pxNeighs[idxTL].components.ptr[ib])();
} else if (directions[0] == down) { } else static if (directionX == down) {
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL]; const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
const posSampling = Point(posSrcX[idxL], posSrcY[idxT]); const posSampling = Point(posSrcX[idxL], posSrcY[idxT]);
const samplingOffset = source.scanTo(posSampling); const samplingOffset = source.scanTo(posSampling);
@ -3138,7 +3132,7 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
} }
return (xSum / nSamples); return (xSum / nSamples);
} else /* if (directions[0] == up) */ { } else /* if (directionX == up) */ {
ulong xSum = 0; ulong xSum = 0;
const ulong[2] weightsX = () { const ulong[2] weightsX = () {
@ -3160,7 +3154,7 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
ulong[2] sampleXDual() { ulong[2] sampleXDual() {
pragma(inline, true); pragma(inline, true);
if (directions[0] == none) { static if (directionX == none) {
return () @trusted { return () @trusted {
ulong[2] result = [ ulong[2] result = [
pxNeighs[idxTL].components.ptr[ib], pxNeighs[idxTL].components.ptr[ib],
@ -3168,7 +3162,7 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
]; ];
return result; return result;
}(); }();
} else if (directions[0] == down) { } else static if (directionX == down) {
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL]; const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
const Point[2] posSampling = [ const Point[2] posSampling = [
Point(posSrcX[idxL], posSrcY[idxT]), Point(posSrcX[idxL], posSrcY[idxT]),
@ -3198,7 +3192,7 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
xSums[] /= nSamples; xSums[] /= nSamples;
return xSums; return xSums;
} else /* if (directions[0] == up) */ { } else /* if (directionX == up) */ {
ulong[2] xSums = [0, 0]; ulong[2] xSums = [0, 0];
const ulong[2] weightsX = () { const ulong[2] weightsX = () {
@ -3240,12 +3234,12 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
return linesSum; return linesSum;
} }
if (directions[0] == none) { static if (directionX == none) {
ySum = foreachLine(delegate(const Point posLine) { ySum = foreachLine(delegate(const Point posLine) {
const pxSrc = source.getPixel(posLine); const pxSrc = source.getPixel(posLine);
return ulong((() @trusted => pxSrc.components.ptr[ib])()); return ulong((() @trusted => pxSrc.components.ptr[ib])());
}); });
} else if (directions[0] == down) { } else static if (directionX == down) {
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL]; const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
ySum = foreachLine(delegate(const Point posLine) { ySum = foreachLine(delegate(const Point posLine) {
@ -3264,7 +3258,7 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
}); });
ySum /= nSamples; ySum /= nSamples;
} else /* if (directions[0] == up) */ { } else /* if (directionX == up) */ {
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL]; const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
ySum = foreachLine(delegate(const Point posLine) { ySum = foreachLine(delegate(const Point posLine) {
@ -3296,11 +3290,11 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
return (ySum / nLines); return (ySum / nLines);
} }
if (directions[idxY] == none) { static if (directionY == none) {
c = clamp255(sampleX()); c = clamp255(sampleX());
} else if (directions[idxY] == down) { } else static if (directionY == down) {
c = clamp255(sampleXMulti()); c = clamp255(sampleXMulti());
} else /* if (directions[idxY] == up) */ { } else /* if (directionY == up) */ {
// looks ass // looks ass
const ulong[2] weightsY = () { const ulong[2] weightsY = () {
ulong[2] result; ulong[2] result;
@ -3328,6 +3322,43 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
++y; ++y;
} }
} }
const Size delta = (target.size - source.size);
const ScalingDirection[2] directions = [
scalingDirectionFromDelta(delta.width),
scalingDirectionFromDelta(delta.height),
];
if (directions[0] == none) {
if (directions[1] == none) {
version (none)
scaleToLinearImpl!(none, none)();
else
return;
} else if (directions[1] == up) {
scaleToLinearImpl!(none, up)();
} else /* if (directions[1] == down) */ {
scaleToLinearImpl!(none, down)();
}
} else if (directions[0] == up) {
if (directions[1] == none) {
scaleToLinearImpl!(up, none)();
} else if (directions[1] == up) {
scaleToLinearImpl!(up, up)();
} else /* if (directions[1] == down) */ {
scaleToLinearImpl!(up, down)();
}
} else /* if (directions[0] == down) */ {
if (directions[1] == none) {
scaleToLinearImpl!(down, none)();
} else if (directions[1] == up) {
scaleToLinearImpl!(down, up)();
} else /* if (directions[1] == down) */ {
scaleToLinearImpl!(down, down)();
}
}
}
} }
// TODO: Document this function // TODO: Document this function